diff --git a/DEPS b/DEPS index f0897ee..a1ee168 100644 --- a/DEPS +++ b/DEPS
@@ -162,11 +162,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': '3c8f9cb45ddefe1e06d75c33a83472ab95ddcfd2', + 'skia_revision': 'f01008997555274463e3616c5b3898d4c97bdfa9', # 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': '861de80c1df35894c6a4c8b6873593c76af8042a', + 'v8_revision': 'd7cac7cb6a468995c1ec48611af283be8fb6c1ab', # 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. @@ -174,7 +174,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '2697f1f03de1b06410dd3f2a6a2e16787be7894d', + 'angle_revision': '76a93c3325f5b1a2a17749dce30ca8ea38622bb6', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -297,7 +297,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'e25a3aede047111f023bfef2ccd8ff84814b5fe5', + 'dawn_revision': 'b9b088f57e3d4567b9441251170cf1719125b2d1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -1105,6 +1105,12 @@ 'condition': 'checkout_linux', }, + # The library for IPP protocol (Chrome OS). + 'src/third_party/libipp/libipp': { + 'url': Var('chromium_git') + '/chromiumos/platform2/libipp.git' + '@' + '6c45a4f3a05cb5dd700414fe4d94cf685159d3ce', + 'condition': 'checkout_linux', + }, + 'src/third_party/libjpeg_turbo': Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + 'd460d6b1cb965c3363f36f7ed716f13d60cdb65d', @@ -1240,7 +1246,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '9c411655515457eb69de44a20697a3d8f7ac2701', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'a203388eab27c235e47d0dee32b52484beaf08bf', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1408,7 +1414,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '0c141c591ae829277053bc1192d136d8a9cb47b2', + Var('webrtc_git') + '/src.git' + '@' + '44bd29a3b068363e013cd425c68fd00dba21d633', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1449,7 +1455,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e7c14e9bac04af07d15aeaaf6624f449be1ebb96', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@9f4081b4ef9bfe0c26c7ffeb33032384562cd8f2', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index 3a8de30..eb47030 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -984,11 +984,12 @@ mojo::PendingReceiver<network::mojom::RestrictedCookieManager> orig_receiver = std::move(*receiver); - network::mojom::RestrictedCookieManagerPtrInfo target_rcm_info; - *receiver = mojo::MakeRequest(&target_rcm_info); + mojo::PendingRemote<network::mojom::RestrictedCookieManager> + target_rcm_remote; + *receiver = target_rcm_remote.InitWithNewPipeAndPassReceiver(); AwProxyingRestrictedCookieManager::CreateAndBind( - std::move(target_rcm_info), is_service_worker, process_id, routing_id, + std::move(target_rcm_remote), is_service_worker, process_id, routing_id, std::move(orig_receiver)); return false; // only made a proxy, still need the actual impl to be made.
diff --git a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc index 6d8a030..628c8ddd 100644 --- a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc +++ b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc
@@ -46,7 +46,7 @@ // static void AwProxyingRestrictedCookieManager::CreateAndBind( - network::mojom::RestrictedCookieManagerPtrInfo underlying_rcm, + mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlying_rcm, bool is_service_worker, int process_id, int frame_id, @@ -163,7 +163,7 @@ } AwProxyingRestrictedCookieManager::AwProxyingRestrictedCookieManager( - network::mojom::RestrictedCookieManagerPtr + mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlying_restricted_cookie_manager, bool is_service_worker, int process_id, @@ -178,15 +178,14 @@ // static void AwProxyingRestrictedCookieManager::CreateAndBindOnIoThread( - network::mojom::RestrictedCookieManagerPtrInfo underlying_rcm, + mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlying_rcm, bool is_service_worker, int process_id, int frame_id, mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); auto wrapper = base::WrapUnique(new AwProxyingRestrictedCookieManager( - network::mojom::RestrictedCookieManagerPtr(std::move(underlying_rcm)), - is_service_worker, process_id, frame_id)); + std::move(underlying_rcm), is_service_worker, process_id, frame_id)); mojo::MakeSelfOwnedReceiver(std::move(wrapper), std::move(receiver)); }
diff --git a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h index fa0d774..27308f4 100644 --- a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h +++ b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "mojo/public/cpp/bindings/remote.h" #include "services/network/public/mojom/restricted_cookie_manager.mojom.h" #include "url/gurl.h" @@ -24,7 +25,8 @@ // // Expects to be called on the UI thread. static void CreateAndBind( - network::mojom::RestrictedCookieManagerPtrInfo underlying_rcm, + mojo::PendingRemote<network::mojom::RestrictedCookieManager> + underlying_rcm, bool is_service_worker, int process_id, int frame_id, @@ -70,20 +72,22 @@ bool AllowCookies(const GURL& url, const GURL& site_for_cookies) const; private: - AwProxyingRestrictedCookieManager(network::mojom::RestrictedCookieManagerPtr - underlying_restricted_cookie_manager, - bool is_service_worker, - int process_id, - int frame_id); + AwProxyingRestrictedCookieManager( + mojo::PendingRemote<network::mojom::RestrictedCookieManager> + underlying_restricted_cookie_manager, + bool is_service_worker, + int process_id, + int frame_id); static void CreateAndBindOnIoThread( - network::mojom::RestrictedCookieManagerPtrInfo underlying_rcm, + mojo::PendingRemote<network::mojom::RestrictedCookieManager> + underlying_rcm, bool is_service_worker, int process_id, int frame_id, mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver); - network::mojom::RestrictedCookieManagerPtr + mojo::Remote<network::mojom::RestrictedCookieManager> underlying_restricted_cookie_manager_; bool is_service_worker_; int process_id_;
diff --git a/android_webview/browser/state_serializer_unittest.cc b/android_webview/browser/state_serializer_unittest.cc index 5cdf3b6..f066cb4 100644 --- a/android_webview/browser/state_serializer_unittest.cc +++ b/android_webview/browser/state_serializer_unittest.cc
@@ -33,8 +33,6 @@ referrer.url = GURL("http://referrer_url"); referrer.policy = network::mojom::ReferrerPolicy::kOrigin; const base::string16 title(base::UTF8ToUTF16("title")); - const content::PageState page_state = - content::PageState::CreateFromEncodedData("completely bogus state"); const bool has_post_data = true; const GURL original_request_url("http://original_request_url"); const GURL base_url_for_data_url("http://base_url"); @@ -47,7 +45,6 @@ entry->SetVirtualURL(virtual_url); entry->SetReferrer(referrer); entry->SetTitle(title); - entry->SetPageState(page_state); entry->SetHasPostData(has_post_data); entry->SetOriginalRequestURL(original_request_url); entry->SetBaseURLForDataURL(base_url_for_data_url);
diff --git a/ash/public/cpp/wallpaper_controller_observer.h b/ash/public/cpp/wallpaper_controller_observer.h index 6d58154..c019fa0 100644 --- a/ash/public/cpp/wallpaper_controller_observer.h +++ b/ash/public/cpp/wallpaper_controller_observer.h
@@ -15,6 +15,9 @@ public: WallpaperControllerObserver(); + // Invoked when the wallpaper is about to change. + virtual void OnWallpaperChanging() {} + // Invoked when the wallpaper is changed. virtual void OnWallpaperChanged() {}
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc index a333d5b..ebe749c 100644 --- a/ash/wallpaper/wallpaper_controller_impl.cc +++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -675,12 +675,16 @@ for (auto& observer : observers_) observer.OnFirstWallpaperShown(); } + for (auto& observer : observers_) - observer.OnWallpaperChanged(); + observer.OnWallpaperChanging(); wallpaper_mode_ = WALLPAPER_IMAGE; InstallDesktopControllerForAllWindows(); ++wallpaper_count_for_testing_; + + for (auto& observer : observers_) + observer.OnWallpaperChanged(); } bool WallpaperControllerImpl::IsPolicyControlled( @@ -1710,10 +1714,9 @@ CustomWallpaperElement(base::FilePath(), image); } -void WallpaperControllerImpl::SetWallpaperFromInfo( - const AccountId& account_id, - const WallpaperInfo& info, - bool show_wallpaper) { +void WallpaperControllerImpl::SetWallpaperFromInfo(const AccountId& account_id, + const WallpaperInfo& info, + bool show_wallpaper) { if (info.type != ONLINE && info.type != DEFAULT) { // This method is meant to be used for ONLINE and DEFAULT types. In // unexpected cases, revert to default wallpaper to fail safely. See @@ -1850,12 +1853,11 @@ CustomWallpaperElement(wallpaper_path, image); } -void WallpaperControllerImpl::OnWallpaperDecoded( - const AccountId& account_id, - const base::FilePath& path, - const WallpaperInfo& info, - bool show_wallpaper, - const gfx::ImageSkia& image) { +void WallpaperControllerImpl::OnWallpaperDecoded(const AccountId& account_id, + const base::FilePath& path, + const WallpaperInfo& info, + bool show_wallpaper, + const gfx::ImageSkia& image) { // Empty image indicates decode failure. Use default wallpaper in this case. if (image.isNull()) { LOG(ERROR) << "Failed to decode user wallpaper at " << path.value()
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc index 804307e..c15fa5e 100644 --- a/ash/wm/overview/overview_grid.cc +++ b/ash/wm/overview/overview_grid.cc
@@ -21,6 +21,7 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_constants.h" #include "ash/shell.h" +#include "ash/wallpaper/wallpaper_controller_impl.h" #include "ash/wm/desks/desk_mini_view.h" #include "ash/wm/desks/desks_bar_view.h" #include "ash/wm/desks/desks_util.h" @@ -70,9 +71,11 @@ // Additional vertical inset reserved for windows in overview mode. constexpr float kOverviewVerticalInset = 0.1f; -// Number of columns and rows for windows in tablet overview mode. +// Number of rows for windows in tablet overview mode. constexpr int kTabletLayoutRow = 2; +constexpr int kMinimumItemsForNewLayout = 6; + // Histogram names for overview enter/exit smoothness in clamshell, // tablet mode and splitview. constexpr char kOverviewEnterClamshellHistogram[] = @@ -376,6 +379,7 @@ void OverviewGrid::Shutdown() { ScreenRotationAnimator::GetForRootWindow(root_window_)->RemoveObserver(this); + Shell::Get()->wallpaper_controller()->RemoveObserver(this); grid_pre_event_handler_.reset(); bool has_non_cover_animating = false; @@ -420,6 +424,7 @@ } grid_pre_event_handler_ = std::make_unique<OverviewGridPreEventHandler>(this); + Shell::Get()->wallpaper_controller()->AddObserver(this); } void OverviewGrid::PositionWindows( @@ -432,7 +437,9 @@ DCHECK_NE(transition, OverviewSession::OverviewTransition::kExit); std::vector<gfx::RectF> rects = - ShouldUseTabletModeGridLayout() + ShouldUseTabletModeGridLayout() && + (window_list_.size() - ignored_items.size() >= + kMinimumItemsForNewLayout) ? GetWindowRectsForTabletModeLayout(ignored_items) : GetWindowRects(ignored_items); @@ -883,6 +890,14 @@ Shell::Get()->overview_controller()->DelayedUpdateRoundedCornersAndShadow(); } +void OverviewGrid::OnWallpaperChanging() { + grid_pre_event_handler_.reset(); +} + +void OverviewGrid::OnWallpaperChanged() { + grid_pre_event_handler_ = std::make_unique<OverviewGridPreEventHandler>(this); +} + void OverviewGrid::OnStartingAnimationComplete(bool canceled) { fps_counter_.reset(); if (canceled) @@ -1319,13 +1334,18 @@ kOverviewScrollHistogram, kOverviewScrollMaxLatencyHistogram); } -void OverviewGrid::UpdateScrollOffset(float delta) { +bool OverviewGrid::UpdateScrollOffset(float delta) { + const float previous_scroll_offset = scroll_offset_; scroll_offset_ += delta; - scroll_offset_ = base::ClampToRange(scroll_offset_, scroll_offset_min_, 0.0f); - PositionWindows(false); + scroll_offset_ = base::ClampToRange(scroll_offset_, scroll_offset_min_, 0.f); + if (scroll_offset_ == previous_scroll_offset) + return false; + + PositionWindows(/*animate=*/false); DCHECK(presentation_time_recorder_); presentation_time_recorder_->RequestNext(); + return true; } void OverviewGrid::EndScroll() {
diff --git a/ash/wm/overview/overview_grid.h b/ash/wm/overview/overview_grid.h index 3d55a15e..30314330 100644 --- a/ash/wm/overview/overview_grid.h +++ b/ash/wm/overview/overview_grid.h
@@ -10,6 +10,7 @@ #include <memory> #include <vector> +#include "ash/public/cpp/wallpaper_controller_observer.h" #include "ash/rotator/screen_rotation_animator_observer.h" #include "ash/wm/overview/overview_session.h" #include "ash/wm/window_state_observer.h" @@ -53,7 +54,8 @@ // it reaches the end of its movement sequence. class ASH_EXPORT OverviewGrid : public aura::WindowObserver, public WindowStateObserver, - public ScreenRotationAnimatorObserver { + public ScreenRotationAnimatorObserver, + public WallpaperControllerObserver { public: OverviewGrid(aura::Window* root_window, const std::vector<aura::Window*>& window_list, @@ -182,6 +184,10 @@ void OnScreenRotationAnimationFinished(ScreenRotationAnimator* animator, bool canceled) override; + // WallpaperControllerObserver: + void OnWallpaperChanging() override; + void OnWallpaperChanged() override; + // Called when overview starting animation completes. void OnStartingAnimationComplete(bool canceled); @@ -272,8 +278,9 @@ void StartScroll(); // |delta| is used for updating |scroll_offset_| with new scroll values so - // that windows in tablet overview mode get positioned accordingly. - void UpdateScrollOffset(float delta); + // that windows in tablet overview mode get positioned accordingly. Returns + // true if the grid was scrolled. + bool UpdateScrollOffset(float delta); void EndScroll();
diff --git a/ash/wm/overview/overview_grid_pre_event_handler.cc b/ash/wm/overview/overview_grid_pre_event_handler.cc index 577c213..8742676 100644 --- a/ash/wm/overview/overview_grid_pre_event_handler.cc +++ b/ash/wm/overview/overview_grid_pre_event_handler.cc
@@ -38,10 +38,12 @@ } OverviewGridPreEventHandler::~OverviewGridPreEventHandler() { + EndFling(); + grid_->EndScroll(); + auto* wallpaper_view = GetWallpaperViewForRoot(grid_->root_window()); if (wallpaper_view) wallpaper_view->RemovePreTargetHandler(this); - EndFling(); } void OverviewGridPreEventHandler::OnMouseEvent(ui::MouseEvent* event) { @@ -96,13 +98,18 @@ gfx::Vector2dF offset; // As a fling progresses, the velocity degenerates, and the difference in - // offset is passed into |grid_| as an updated scroll value. - bool fling = + // offset is passed into |grid_| as an updated scroll value. Stop flinging if + // the API for fling says to finish, or we reach one of the edges of the + // overview grid. + bool continue_fling = fling_curve_->ComputeScrollOffset(timestamp, &offset, &fling_velocity_); - grid_->UpdateScrollOffset(offset.x() - fling_last_offset_.x()); - fling_last_offset_ = offset; + if (!continue_fling) { + continue_fling = grid_->UpdateScrollOffset( + fling_last_offset_ ? offset.x() - fling_last_offset_->x() : offset.x()); + } + fling_last_offset_ = base::make_optional(offset); - if (!fling) + if (!continue_fling) EndFling(); } @@ -137,6 +144,7 @@ observed_compositor_->RemoveAnimationObserver(this); observed_compositor_ = nullptr; fling_curve_.reset(); + fling_last_offset_ = base::nullopt; grid_->EndScroll(); }
diff --git a/ash/wm/overview/overview_grid_pre_event_handler.h b/ash/wm/overview/overview_grid_pre_event_handler.h index 8ef02f6..81568b09 100644 --- a/ash/wm/overview/overview_grid_pre_event_handler.h +++ b/ash/wm/overview/overview_grid_pre_event_handler.h
@@ -6,6 +6,7 @@ #define ASH_WM_OVERVIEW_OVERVIEW_GRID_PRE_EVENT_HANDLER_H_ #include "base/macros.h" +#include "base/optional.h" #include "ui/compositor/compositor_animation_observer.h" #include "ui/events/event_handler.h" #include "ui/gfx/geometry/point.h" @@ -61,7 +62,7 @@ // Cached value of an earlier offset that determines values to scroll through // overview mode by being compared to an updated offset. - gfx::Vector2dF fling_last_offset_; + base::Optional<gfx::Vector2dF> fling_last_offset_; // The compositor we are observing when a fling is underway. ui::Compositor* observed_compositor_ = nullptr;
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc index 3bb58b52..3eaa7e2 100644 --- a/ash/wm/overview/overview_item.cc +++ b/ash/wm/overview/overview_item.cc
@@ -780,6 +780,7 @@ HandleGestureEventForTabletModeLayout(event); return; } + const gfx::PointF location = event->details().bounding_box_f().CenterPoint(); switch (event->type()) { case ui::ET_GESTURE_TAP_DOWN: @@ -820,8 +821,12 @@ overview_grid()->grid_pre_event_handler()->OnGestureEvent(event); break; case ui::ET_SCROLL_FLING_START: - HandleFlingStartEvent(location, event->details().velocity_x(), - event->details().velocity_y()); + if (IsDragItem()) { + HandleFlingStartEvent(location, event->details().velocity_x(), + event->details().velocity_y()); + } else { + overview_grid()->grid_pre_event_handler()->OnGestureEvent(event); + } break; case ui::ET_GESTURE_SCROLL_END: if (IsDragItem())
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc index 9a65621..b56adb9 100644 --- a/ash/wm/overview/overview_session.cc +++ b/ash/wm/overview/overview_session.cc
@@ -67,6 +67,11 @@ SkColorSetA(SK_ColorBLACK, 204); constexpr SkColor kNoItemsIndicatorTextColor = SK_ColorWHITE; +// Values for scrolling the grid by using the keyboard. +// TODO(sammiequon): See if we can use the same values used for web scrolling. +constexpr int kKeyboardPressScrollingDp = 25; +constexpr int kKeyboardHoldScrollingDp = 5; + // Returns the bounds for the overview window grid according to the split view // state. If split view mode is active, the overview window should open on the // opposite side of the default snap window. If |divider_changed| is true, maybe @@ -840,7 +845,11 @@ return; } - if (event->type() != ui::ET_KEY_PRESSED) + const bool process_released_key_event = + (event->key_code() == ui::VKEY_LEFT || + event->key_code() == ui::VKEY_RIGHT) && + ShouldUseTabletModeGridLayout(); + if (event->type() != ui::ET_KEY_PRESSED && !process_released_key_event) return; switch (event->key_code()) { @@ -857,17 +866,22 @@ Move(/*reverse=*/false); break; case ui::VKEY_RIGHT: - case ui::VKEY_TAB: - if (event->key_code() == ui::VKEY_RIGHT || - !(event->flags() & ui::EF_SHIFT_DOWN)) { + if (!ProcessForScrolling(*event)) { ++num_key_presses_; Move(/*reverse=*/false); - break; } - FALLTHROUGH; - case ui::VKEY_LEFT: + break; + case ui::VKEY_TAB: { + const bool reverse = event->flags() & ui::EF_SHIFT_DOWN; ++num_key_presses_; - Move(/*reverse=*/true); + Move(reverse); + break; + } + case ui::VKEY_LEFT: + if (!ProcessForScrolling(*event)) { + ++num_key_presses_; + Move(/*reverse=*/true); + } break; case ui::VKEY_W: { if (!(event->flags() & ui::EF_CONTROL_DOWN)) @@ -986,6 +1000,37 @@ highlight_controller_->MoveHighlight(reverse); } +bool OverviewSession::ProcessForScrolling(const ui::KeyEvent& event) { + if (!ShouldUseTabletModeGridLayout() || + !(event.flags() & ui::EF_CONTROL_DOWN)) { + return false; + } + + const bool press = (event.type() == ui::ET_KEY_PRESSED); + const bool repeat = event.is_repeat(); + DCHECK(event.key_code() == ui::VKEY_LEFT || + event.key_code() == ui::VKEY_RIGHT); + const bool reverse = event.key_code() == ui::VKEY_LEFT; + + // TODO(sammiequon): This only works for tablet mode at the moment, so using + // the primary display works. If this feature is adapted for multi display + // then this needs to be revisited. + auto* grid = GetGridWithRootWindow(Shell::GetPrimaryRootWindow()); + if (press && !repeat) { + grid->StartScroll(); + grid->UpdateScrollOffset(kKeyboardPressScrollingDp * (reverse ? 1 : -1)); + return true; + } + + if (press && repeat) { + grid->UpdateScrollOffset(kKeyboardHoldScrollingDp * (reverse ? 1 : -1)); + return true; + } + + grid->EndScroll(); + return true; +} + void OverviewSession::RemoveAllObservers() { for (auto* window : observed_windows_) window->RemoveObserver(this);
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h index eb0cdd4..5432b9a 100644 --- a/ash/wm/overview/overview_session.h +++ b/ash/wm/overview/overview_session.h
@@ -311,6 +311,10 @@ // the corresponding window grid. void Move(bool reverse); + // Helper function that processes a key event and maybe scrolls the overview + // grid on the primary display. + bool ProcessForScrolling(const ui::KeyEvent& event); + // Removes all observers that were registered during construction and/or // initialization. void RemoveAllObservers();
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc index afe2a8f..ce3f9551 100644 --- a/ash/wm/overview/overview_session_unittest.cc +++ b/ash/wm/overview/overview_session_unittest.cc
@@ -2813,6 +2813,15 @@ GetEventGenerator()->Dispatch(&long_press); } + // Creates |n| test windows. They are created in reverse order, so that the + // first window in the vector is the MRU window. + std::vector<std::unique_ptr<aura::Window>> CreateTestWindows(int n) { + std::vector<std::unique_ptr<aura::Window>> windows(n); + for (int i = n - 1; i >= 0; --i) + windows[i] = CreateTestWindow(); + return windows; + } + // TODO(sammiequon): Investigate simulating fling event for testing inertial // scrolling. @@ -2824,23 +2833,14 @@ // Tests that windows are in proper positions in the new overview layout. TEST_F(OverviewSessionNewLayoutTest, CheckNewLayoutWindowPositions) { - // Windows are created in this order because overview orders windows in terms - // of most recently used. |window4| will be created first, but will be - // determined last recently used. |window1| will be created last, but will be - // determined most recently used. Thus this order will be reflected in - // overview mode. - std::unique_ptr<aura::Window> window4 = CreateTestWindow(); - std::unique_ptr<aura::Window> window3 = CreateTestWindow(); - std::unique_ptr<aura::Window> window2 = CreateTestWindow(); - std::unique_ptr<aura::Window> window1 = CreateTestWindow(); - + auto windows = CreateTestWindows(6); ToggleOverview(); ASSERT_TRUE(InOverviewSession()); - OverviewItem* item1 = GetOverviewItemForWindow(window1.get()); - OverviewItem* item2 = GetOverviewItemForWindow(window2.get()); - OverviewItem* item3 = GetOverviewItemForWindow(window3.get()); - OverviewItem* item4 = GetOverviewItemForWindow(window4.get()); + OverviewItem* item1 = GetOverviewItemForWindow(windows[0].get()); + OverviewItem* item2 = GetOverviewItemForWindow(windows[1].get()); + OverviewItem* item3 = GetOverviewItemForWindow(windows[2].get()); + OverviewItem* item4 = GetOverviewItemForWindow(windows[3].get()); const gfx::RectF item1_bounds = item1->target_bounds(); const gfx::RectF item2_bounds = item2->target_bounds(); @@ -2864,15 +2864,7 @@ } TEST_F(OverviewSessionNewLayoutTest, CheckOffscreenWindows) { - // Windows are created in this order because overview orders windows in terms - // of most recently used. |window|7|| will be created first, but will be - // determined last recently used. |window|0|| will be created last, but will - // be determined most recently used. Thus this order will be reflected in - // overview mode. - std::vector<std::unique_ptr<aura::Window>> windows(8); - for (int i = 7; i >= 0; --i) - windows[i] = CreateTestWindow(); - + auto windows = CreateTestWindows(8); ToggleOverview(); ASSERT_TRUE(InOverviewSession()); @@ -2901,10 +2893,7 @@ // Tests to see if windows are not shifted if all already available windows // fit on screen. TEST_F(OverviewSessionNewLayoutTest, CheckNoOverviewItemShift) { - std::vector<std::unique_ptr<aura::Window>> windows(4); - for (int i = 3; i >= 0; --i) - windows[i] = CreateTestWindow(); - + auto windows = CreateTestWindows(4); ToggleOverview(); ASSERT_TRUE(InOverviewSession()); @@ -2918,10 +2907,7 @@ // Tests to see if windows are shifted if at least one window is // partially/completely positioned offscreen. TEST_F(OverviewSessionNewLayoutTest, CheckOverviewItemShift) { - std::vector<std::unique_ptr<aura::Window>> windows(7); - for (int i = 6; i >= 0; --i) - windows[i] = CreateTestWindow(); - + auto windows = CreateTestWindows(7); ToggleOverview(); ASSERT_TRUE(InOverviewSession()); @@ -2934,15 +2920,12 @@ // Tests to see if windows remain in bounds after scrolling extremely far. TEST_F(OverviewSessionNewLayoutTest, CheckOverviewItemScrollingBounds) { - std::vector<std::unique_ptr<aura::Window>> windows(8); - for (int i = 7; i >= 0; --i) - windows[i] = CreateTestWindow(); - + auto windows = CreateTestWindows(8); ToggleOverview(); ASSERT_TRUE(InOverviewSession()); // Scroll an extreme amount to see if windows on the far left are still in - // bounds. First, align the left-most window (|windows|0||) to the left-hand + // bounds. First, align the left-most window (|windows[0]|) to the left-hand // bound and store the item's location. Then, scroll a far amount and check to // see if the item moved at all. OverviewItem* leftmost_window = GetOverviewItemForWindow(windows[0].get()); @@ -2953,7 +2936,7 @@ EXPECT_EQ(left_bounds, leftmost_window->target_bounds()); // Scroll an extreme amount to see if windows on the far right are still in - // bounds. First, align the right-most window (|windows|7||) to the right-hand + // bounds. First, align the right-most window (|windows[7]|) to the right-hand // bound and store the item's location. Then, scroll a far amount and check to // see if the item moved at all. OverviewItem* rightmost_window = GetOverviewItemForWindow(windows[7].get()); @@ -2996,10 +2979,7 @@ // Test that scrolling occurs if started on top of a window using the window's // center-point as a start. TEST_F(OverviewSessionNewLayoutTest, CheckScrollingOnWindowItems) { - std::vector<std::unique_ptr<aura::Window>> windows(8); - for (int i = 7; i >= 0; --i) - windows[i] = CreateTestWindow(); - + auto windows = CreateTestWindows(8); ToggleOverview(); ASSERT_TRUE(InOverviewSession()); @@ -3012,24 +2992,35 @@ EXPECT_LT(leftmost_window->target_bounds(), left_bounds); } +// Test that scrolling occurs if we hit the associated keyboard shortcut. +TEST_F(OverviewSessionNewLayoutTest, CheckScrollingWithKeyboardShortcut) { + auto windows = CreateTestWindows(8); + ToggleOverview(); + ASSERT_TRUE(InOverviewSession()); + + OverviewItem* leftmost_window = GetOverviewItemForWindow(windows[0].get()); + const gfx::RectF left_bounds = leftmost_window->target_bounds(); + + SendKey(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN); + EXPECT_LT(leftmost_window->target_bounds(), left_bounds); +} + // Test that tapping a window in overview closes overview mode. TEST_F(OverviewSessionNewLayoutTest, CheckWindowActivateOnTap) { base::UserActionTester user_action_tester; - std::vector<std::unique_ptr<aura::Window>> windows(8); - for (int i = 7; i >= 0; --i) - windows[i] = CreateTestWindow(); + auto windows = CreateTestWindows(8); wm::ActivateWindow(windows[1].get()); ToggleOverview(); ASSERT_TRUE(InOverviewSession()); - // Tap on |windows|1|| to exit overview. + // Tap on |windows[1]| to exit overview. GetEventGenerator()->GestureTapAt( GetTransformedTargetBounds(windows[1].get()).CenterPoint()); EXPECT_EQ( 0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview)); - // |windows|1|| remains active. Click on it to exit overview. + // |windows[1]| remains active. Click on it to exit overview. ASSERT_EQ(windows[1].get(), window_util::GetFocusedWindow()); ToggleOverview(); ClickWindow(windows[1].get());
diff --git a/base/BUILD.gn b/base/BUILD.gn index 824dfad3..973cc6f 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1061,6 +1061,8 @@ "win/event_trace_controller.h", "win/event_trace_provider.cc", "win/event_trace_provider.h", + "win/file_pre_reader.cc", + "win/file_pre_reader.h", "win/hstring_compare.cc", "win/hstring_compare.h", "win/hstring_reference.cc", @@ -2259,7 +2261,10 @@ ] if (!is_ios) { # iOS doesn't use the partition allocator, therefore it can't run this test. - sources += [ "allocator/partition_allocator/partition_alloc_perftest.cc" ] + sources += [ + "allocator/partition_allocator/partition_alloc_perftest.cc", + "allocator/partition_allocator/spin_lock_perftest.cc", + ] } deps = [ ":base",
diff --git a/base/allocator/partition_allocator/page_allocator_internals_posix.h b/base/allocator/partition_allocator/page_allocator_internals_posix.h index c3b668b..b49b80a3 100644 --- a/base/allocator/partition_allocator/page_allocator_internals_posix.h +++ b/base/allocator/partition_allocator/page_allocator_internals_posix.h
@@ -16,18 +16,39 @@ #include <mach/mach.h> #endif +#if defined(OS_ANDROID) +#include <sys/prctl.h> +#endif #if defined(OS_LINUX) #include <sys/resource.h> #include <algorithm> #endif +#include "base/allocator/partition_allocator/page_allocator.h" + #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS MAP_ANON #endif namespace base { +#if defined(OS_ANDROID) +namespace { +const char* PageTagToName(PageTag tag) { + switch (tag) { + case PageTag::kChromium: + return "chromium"; + case PageTag::kV8: + return "v8"; + default: + DCHECK(false); + return ""; + } +} +} // namespace +#endif // defined(OS_ANDROID) + // |mmap| uses a nearby address if the hint address is blocked. constexpr bool kHintIsAdvisory = true; std::atomic<int32_t> s_allocPageErrorCode{0}; @@ -91,6 +112,17 @@ s_allocPageErrorCode = errno; ret = nullptr; } + +#if defined(OS_ANDROID) + // On Android, anonymous mappings can have a name attached to them. This is + // useful for debugging, and double-checking memory attribution. + if (ret) { + // No error checking on purpose, testing only. + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ret, length, + PageTagToName(page_tag)); + } +#endif + return ret; }
diff --git a/base/allocator/partition_allocator/page_allocator_unittest.cc b/base/allocator/partition_allocator/page_allocator_unittest.cc index 3f162fd..7612ad2 100644 --- a/base/allocator/partition_allocator/page_allocator_unittest.cc +++ b/base/allocator/partition_allocator/page_allocator_unittest.cc
@@ -6,9 +6,15 @@ #include <stdlib.h> #include <string.h> +#include <algorithm> +#include <string> +#include <vector> #include "base/allocator/partition_allocator/address_space_randomization.h" #include "build/build_config.h" +#if defined(OS_ANDROID) +#include "base/debug/proc_maps_linux.h" +#endif // defined(OS_ANDROID) #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_POSIX) @@ -219,6 +225,32 @@ #endif // defined(OS_POSIX) +#if defined(OS_ANDROID) +TEST(PageAllocatorTest, PageTagging) { + void* buffer = AllocPages(nullptr, kPageAllocationGranularity, + kPageAllocationGranularity, PageInaccessible, + PageTag::kChromium, true); + EXPECT_TRUE(buffer); + + std::string proc_maps; + EXPECT_TRUE(debug::ReadProcMaps(&proc_maps)); + std::vector<debug::MappedMemoryRegion> regions; + EXPECT_TRUE(debug::ParseProcMaps(proc_maps, ®ions)); + + bool found = false; + for (const auto& region : regions) { + if (region.start == reinterpret_cast<uintptr_t>(buffer)) { + found = true; + EXPECT_EQ("[anon:chromium]", region.path); + break; + } + } + + FreePages(buffer, kPageAllocationGranularity); + EXPECT_TRUE(found); +} +#endif // defined(OS_ANDROID) + } // namespace base #endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
diff --git a/base/allocator/partition_allocator/spin_lock_perftest.cc b/base/allocator/partition_allocator/spin_lock_perftest.cc new file mode 100644 index 0000000..49811cb --- /dev/null +++ b/base/allocator/partition_allocator/spin_lock_perftest.cc
@@ -0,0 +1,86 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/allocator/partition_allocator/spin_lock.h" +#include "base/threading/platform_thread.h" +#include "base/time/time.h" +#include "base/timer/lap_timer.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/perf/perf_test.h" + +namespace base { +namespace { + +constexpr int kWarmupRuns = 1; +constexpr TimeDelta kTimeLimit = TimeDelta::FromSeconds(1); +constexpr int kTimeCheckInterval = 100000; + +class Spin : public PlatformThread::Delegate { + public: + Spin(subtle::SpinLock* lock, size_t* data) + : lock_(lock), data_(data), should_stop_(false) {} + ~Spin() override = default; + + void ThreadMain() override { + while (!should_stop_.load(std::memory_order_relaxed)) { + lock_->lock(); + (*data_)++; + lock_->unlock(); + } + } + + void Stop() { should_stop_ = true; } + + private: + subtle::SpinLock* lock_; + size_t* data_; + std::atomic<bool> should_stop_; +}; + +} // namespace + +TEST(SpinLockPerfTest, Simple) { + LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval); + size_t data = 0; + + subtle::SpinLock lock; + + do { + lock.lock(); + data += 1; + lock.unlock(); + timer.NextLap(); + } while (!timer.HasTimeLimitExpired()); + + perf_test::PrintResult("SpinLockPerfTest", " lock()/unlock()", "", + timer.LapsPerSecond(), "runs/s", true); +} + +TEST(SpinLockPerfTest, WithCompetingThread) { + LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval); + size_t data = 0; + + subtle::SpinLock lock; + + // Starts a competing thread executing the same loop as this thread. + Spin thread_main(&lock, &data); + PlatformThreadHandle thread_handle; + ASSERT_TRUE(PlatformThread::Create(0, &thread_main, &thread_handle)); + + do { + lock.lock(); + data += 1; + lock.unlock(); + timer.NextLap(); + } while (!timer.HasTimeLimitExpired()); + + thread_main.Stop(); + PlatformThread::Join(thread_handle); + + perf_test::PrintResult("SpinLockPerfTest.WithCompetingThread", + " lock()/unlock()", "", timer.LapsPerSecond(), + "runs/s", true); +} + +} // namespace base
diff --git a/base/process/launch.h b/base/process/launch.h index 5b9612d0..24fb4273 100644 --- a/base/process/launch.h +++ b/base/process/launch.h
@@ -254,6 +254,10 @@ // child process' namespace. Paths installed by |paths_to_clone| will be // overridden by these entries. std::vector<PathToTransfer> paths_to_transfer; + + // Suffix that will be added to the process name. When specified process name + // will be set to "<binary_name><process_suffix>". + std::string process_name_suffix; #endif // defined(OS_FUCHSIA) #if defined(OS_POSIX)
diff --git a/base/process/launch_fuchsia.cc b/base/process/launch_fuchsia.cc index 34cbaad7..dea0fce 100644 --- a/base/process/launch_fuchsia.cc +++ b/base/process/launch_fuchsia.cc
@@ -91,6 +91,12 @@ return action; } +fdio_spawn_action_t FdioSpawnActionSetName(const char* name) { + fdio_spawn_action_t action = FdioSpawnAction(FDIO_SPAWN_ACTION_SET_NAME); + action.name.data = name; + return action; +} + } // namespace // static @@ -206,6 +212,15 @@ FdioSpawnActionCloneFd(src_target.first, src_target.second)); } + // If |process_name_suffix| is specified then set process name as + // "<file_name><suffix>", otherwise leave the default value. + std::string process_name; + if (!options.process_name_suffix.empty()) { + process_name = base::FilePath(argv[0]).BaseName().value() + + options.process_name_suffix; + spawn_actions.push_back(FdioSpawnActionSetName(process_name.c_str())); + } + zx::process process_handle; // fdio_spawn_etc() will write a null-terminated scring to |error_message| in // case of failure, so we avoid unnecessarily initializing it here.
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc index 621aec5..cee182c 100644 --- a/base/process/process_util_unittest.cc +++ b/base/process/process_util_unittest.cc
@@ -476,6 +476,22 @@ EXPECT_EQ(ZX_ERR_BAD_HANDLE, zx_handle_close(handles[0].get())); ignore_result(handles[0].release()); } + +TEST_F(ProcessUtilTest, FuchsiaProcessNameSuffix) { + LaunchOptions options; + options.process_name_suffix = "#test"; + Process process(SpawnChildWithOptions("SimpleChildProcess", options)); + + char name[256] = {}; + size_t name_size = sizeof(name); + zx_status_t status = + zx_object_get_property(process.Handle(), ZX_PROP_NAME, name, name_size); + ASSERT_EQ(status, ZX_OK); + EXPECT_EQ(std::string(name), + CommandLine::ForCurrentProcess()->GetProgram().BaseName().value() + + "#test"); +} + #endif // defined(OS_FUCHSIA) // On Android SpawnProcess() doesn't use LaunchProcess() and doesn't support
diff --git a/base/task/post_job.cc b/base/task/post_job.cc index e57b32e..df0a981 100644 --- a/base/task/post_job.cc +++ b/base/task/post_job.cc
@@ -5,49 +5,16 @@ #include "base/task/post_job.h" #include "base/task/thread_pool/job_task_source.h" -#include "base/task/thread_pool/pooled_task_runner_delegate.h" namespace base { namespace experimental { -JobDelegate::JobDelegate( - internal::JobTaskSource* task_source, - internal::PooledTaskRunnerDelegate* pooled_task_runner_delegate) - : task_source_(task_source), - pooled_task_runner_delegate_(pooled_task_runner_delegate) { - DCHECK(task_source_); - DCHECK(pooled_task_runner_delegate_); -#if DCHECK_IS_ON() - recorded_increase_version_ = task_source_->GetConcurrencyIncreaseVersion(); - // Record max concurrency before running the worker task. - recorded_max_concurrency_ = task_source_->GetMaxConcurrency(); -#endif // DCHECK_IS_ON() -} - -JobDelegate::~JobDelegate() { -#if DCHECK_IS_ON() - // When ShouldYield() returns false, the worker task is expected to do - // work before returning. - size_t expected_max_concurrency = recorded_max_concurrency_; - if (!last_should_yield_ && expected_max_concurrency > 0) - --expected_max_concurrency; - AssertExpectedConcurrency(expected_max_concurrency); -#endif // DCHECK_IS_ON() -} +JobDelegate::JobDelegate(internal::JobTaskSource* task_source) + : task_source_(task_source) {} bool JobDelegate::ShouldYield() { -#if DCHECK_IS_ON() - // ShouldYield() shouldn't be called again after returning true. - DCHECK(!last_should_yield_); - AssertExpectedConcurrency(recorded_max_concurrency_); -#endif // DCHECK_IS_ON() - const bool should_yield = - pooled_task_runner_delegate_->ShouldYield(task_source_); - -#if DCHECK_IS_ON() - last_should_yield_ = should_yield; -#endif // DCHECK_IS_ON() - return should_yield; + // TODO(crbug.com/839091): Implement this. + return false; } void JobDelegate::YieldIfNeeded() { @@ -58,45 +25,5 @@ task_source_->NotifyConcurrencyIncrease(); } -void JobDelegate::AssertExpectedConcurrency(size_t expected_max_concurrency) { - // In dcheck builds, verify that max concurrency falls in one of the following - // cases: - // 1) max concurrency behaves normally and is below or equals the expected - // value. - // 2) max concurrency increased above the expected value, which implies - // there are new work items that the associated worker task didn't see and - // NotifyConcurrencyIncrease() should be called to adjust the number of - // worker. - // a) NotifyConcurrencyIncrease() was already called and the recorded - // concurrency version is out of date, i.e. less than the actual version. - // b) NotifyConcurrencyIncrease() has not yet been called, in which case the - // function waits for an imminent increase of the concurrency version. - // This prevent ill-formed GetMaxConcurrency() implementations that: - // - Don't decrease with the number of remaining work items. - // - Don't return an up-to-date value. -#if DCHECK_IS_ON() - // Case 1: - const size_t max_concurrency = task_source_->GetMaxConcurrency(); - if (max_concurrency <= expected_max_concurrency) - return; - - // Case 2a: - const size_t actual_version = task_source_->GetConcurrencyIncreaseVersion(); - DCHECK_LE(recorded_increase_version_, actual_version); - if (recorded_increase_version_ < actual_version) - return; - - // Case 2b: - const bool updated = task_source_->WaitForConcurrencyIncreaseUpdate( - recorded_increase_version_); - DCHECK(updated) - << "Value returned by |max_concurrency_callback| is expected to " - "decrease, unless NotifyConcurrencyIncrease() is called."; - - recorded_increase_version_ = task_source_->GetConcurrencyIncreaseVersion(); - recorded_max_concurrency_ = task_source_->GetMaxConcurrency(); -#endif // DCHECK_IS_ON() -} - } // namespace experimental } // namespace base \ No newline at end of file
diff --git a/base/task/post_job.h b/base/task/post_job.h index de6b2d6..94ab75c 100644 --- a/base/task/post_job.h +++ b/base/task/post_job.h
@@ -6,14 +6,12 @@ #define BASE_TASK_POST_JOB_H_ #include "base/base_export.h" -#include "base/logging.h" #include "base/macros.h" #include "base/time/time.h" namespace base { namespace internal { class JobTaskSource; -class PooledTaskRunnerDelegate; } namespace experimental { @@ -21,13 +19,7 @@ // communicate with the scheduler. class BASE_EXPORT JobDelegate { public: - // A JobDelegate is instantiated for each worker task that is run. - // |task_source| is the task source whose worker task is running with this - // delegate and |pooled_task_runner_delegate| provides communication with the - // thread pool. - JobDelegate(internal::JobTaskSource* task_source, - internal::PooledTaskRunnerDelegate* pooled_task_runner_delegate); - ~JobDelegate(); + explicit JobDelegate(internal::JobTaskSource* task_source); // Returns true if this thread should return from the worker task on the // current thread ASAP. Workers should periodically invoke ShouldYield (or @@ -46,25 +38,7 @@ void NotifyConcurrencyIncrease(); private: - // Verifies that either max concurrency is lower or equal to - // |expected_max_concurrency|, or there is an increase version update - // triggered by NotifyConcurrencyIncrease(). - void AssertExpectedConcurrency(size_t expected_max_concurrency); - internal::JobTaskSource* const task_source_; - internal::PooledTaskRunnerDelegate* const pooled_task_runner_delegate_; - -#if DCHECK_IS_ON() - // Used in AssertExpectedConcurrency(), see that method's impl for details. - // Value of max concurrency recorded before running the worker task. - size_t recorded_max_concurrency_; - // Value of the increase version recorded before running the worker task. - size_t recorded_increase_version_; - // Value returned by the last call to ShouldYield(). - bool last_should_yield_ = false; -#endif - - DISALLOW_COPY_AND_ASSIGN(JobDelegate); }; } // namespace experimental
diff --git a/base/task/thread_pool/job_task_source.cc b/base/task/thread_pool/job_task_source.cc index c6e5f97..25ff987 100644 --- a/base/task/thread_pool/job_task_source.cc +++ b/base/task/thread_pool/job_task_source.cc
@@ -11,10 +11,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/task/task_features.h" -#include "base/task/thread_pool/pooled_task_runner_delegate.h" -#include "base/threading/thread_restrictions.h" #include "base/time/time.h" -#include "base/time/time_override.h" namespace base { namespace internal { @@ -23,8 +20,7 @@ const Location& from_here, const TaskTraits& traits, RepeatingCallback<void(experimental::JobDelegate*)> worker_task, - RepeatingCallback<size_t()> max_concurrency_callback, - PooledTaskRunnerDelegate* delegate) + RepeatingCallback<size_t()> max_concurrency_callback) : TaskSource(traits, nullptr, TaskSourceExecutionMode::kJob), from_here_(from_here), max_concurrency_callback_(std::move(max_concurrency_callback)), @@ -33,15 +29,14 @@ const RepeatingCallback<void(experimental::JobDelegate*)>& worker_task) { // Each worker task has its own delegate with associated state. - experimental::JobDelegate job_delegate{self, self->delegate_}; + // TODO(crbug.com/839091): Implement assertions on max concurrency + // increase in the delegate. + experimental::JobDelegate job_delegate{self}; worker_task.Run(&job_delegate); }, base::Unretained(this), std::move(worker_task))), - queue_time_(TimeTicks::Now()), - delegate_(delegate) { - DCHECK(delegate_); -} + queue_time_(TimeTicks::Now()) {} JobTaskSource::~JobTaskSource() { #if DCHECK_IS_ON() @@ -105,52 +100,16 @@ } void JobTaskSource::NotifyConcurrencyIncrease() { -#if DCHECK_IS_ON() - { - AutoLock auto_lock(version_lock_); - ++increase_version_; - version_condition_.Broadcast(); - } -#endif // DCHECK_IS_ON() - // Make sure the task source is in the queue if not already. - // Caveat: it's possible but unlikely that the task source has already reached - // its intended concurrency and doesn't need to be enqueued if there - // previously were too many worker. For simplicity, the task source is always - // enqueued and will get discarded if already saturated when it is popped from - // the priority queue. - delegate_->EnqueueJobTaskSource(this); + // TODO(839091): Implement this. } size_t JobTaskSource::GetMaxConcurrency() const { return max_concurrency_callback_.Run(); } -#if DCHECK_IS_ON() - -size_t JobTaskSource::GetConcurrencyIncreaseVersion() const { - AutoLock auto_lock(version_lock_); - return increase_version_; -} - -bool JobTaskSource::WaitForConcurrencyIncreaseUpdate(size_t recorded_version) { - AutoLock auto_lock(version_lock_); - constexpr TimeDelta timeout = TimeDelta::FromSeconds(1); - const base::TimeTicks start_time = subtle::TimeTicksNowIgnoringOverride(); - do { - DCHECK_LE(recorded_version, increase_version_); - if (recorded_version != increase_version_) - return true; - // Waiting is acceptable because it is in DCHECK-only code. - ScopedAllowBaseSyncPrimitivesOutsideBlockingScope - allow_base_sync_primitives; - version_condition_.TimedWait(timeout); - } while (subtle::TimeTicksNowIgnoringOverride() - start_time < timeout); - return false; -} - -#endif // DCHECK_IS_ON() - Optional<Task> JobTaskSource::TakeTask(TaskSource::Transaction* transaction) { + // JobTaskSource members are not lock-protected so no need to acquire a lock + // if |transaction| is nullptr. DCHECK_GT(worker_count_.load(std::memory_order_relaxed), 0U); DCHECK(worker_task_); return base::make_optional<Task>(from_here_, worker_task_, TimeDelta());
diff --git a/base/task/thread_pool/job_task_source.h b/base/task/thread_pool/job_task_source.h index ddaca19..58000b0 100644 --- a/base/task/thread_pool/job_task_source.h +++ b/base/task/thread_pool/job_task_source.h
@@ -14,8 +14,6 @@ #include "base/callback.h" #include "base/macros.h" #include "base/optional.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" #include "base/task/post_job.h" #include "base/task/task_traits.h" #include "base/task/thread_pool/sequence_sort_key.h" @@ -25,8 +23,6 @@ namespace base { namespace internal { -class PooledTaskRunnerDelegate; - // A JobTaskSource generates many Tasks from a single RepeatingClosure. // // Derived classes control the intended concurrency with GetMaxConcurrency(). @@ -35,8 +31,7 @@ JobTaskSource(const Location& from_here, const TaskTraits& traits, RepeatingCallback<void(experimental::JobDelegate*)> worker_task, - RepeatingCallback<size_t()> max_concurrency_callback, - PooledTaskRunnerDelegate* delegate); + RepeatingCallback<size_t()> max_concurrency_callback); // Notifies this task source that max concurrency was increased, and the // number of worker should be adjusted. @@ -46,23 +41,17 @@ ExecutionEnvironment GetExecutionEnvironment() override; size_t GetRemainingConcurrency() const override; - // Returns the maximum number of tasks from this TaskSource that can run - // concurrently. - size_t GetMaxConcurrency() const; - -#if DCHECK_IS_ON() - size_t GetConcurrencyIncreaseVersion() const; - // Returns true if the concurrency version was updated above - // |recorded_version|, or false on timeout. - bool WaitForConcurrencyIncreaseUpdate(size_t recorded_version); -#endif // DCHECK_IS_ON() - private: static constexpr size_t kInvalidWorkerCount = std::numeric_limits<size_t>::max(); ~JobTaskSource() override; + // Returns the maximum number of tasks from this TaskSource that can run + // concurrently. The implementation can only return values lower than or equal + // to previously returned values. + size_t GetMaxConcurrency() const; + // TaskSource: RunStatus WillRunTask() override; Optional<Task> TakeTask(TaskSource::Transaction* transaction) override; @@ -78,16 +67,6 @@ base::RepeatingCallback<size_t()> max_concurrency_callback_; base::RepeatingClosure worker_task_; const TimeTicks queue_time_; - PooledTaskRunnerDelegate* delegate_; - -#if DCHECK_IS_ON() - // Synchronizes accesses to |increase_version_|. - mutable Lock version_lock_; - // Signaled whenever increase_version_ is updated. - ConditionVariable version_condition_{&version_lock_}; - // Incremented every time max concurrency is increased. - size_t increase_version_ GUARDED_BY(version_lock_) = 0; -#endif // DCHECK_IS_ON() DISALLOW_COPY_AND_ASSIGN(JobTaskSource); };
diff --git a/base/task/thread_pool/job_task_source_unittest.cc b/base/task/thread_pool/job_task_source_unittest.cc index 8d911a5..0483011 100644 --- a/base/task/thread_pool/job_task_source_unittest.cc +++ b/base/task/thread_pool/job_task_source_unittest.cc
@@ -8,45 +8,20 @@ #include "base/bind_helpers.h" #include "base/memory/ptr_util.h" -#include "base/task/thread_pool/pooled_task_runner_delegate.h" #include "base/task/thread_pool/test_utils.h" #include "base/test/bind_test_util.h" #include "base/test/gtest_util.h" -#include "base/test/test_timeouts.h" -#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -using ::testing::_; -using ::testing::Return; - namespace base { namespace internal { -class MockPooledTaskRunnerDelegate : public PooledTaskRunnerDelegate { - public: - MOCK_METHOD2(PostTaskWithSequence, - bool(Task task, scoped_refptr<Sequence> sequence)); - MOCK_CONST_METHOD1(ShouldYield, bool(TaskSource* task_source)); - MOCK_METHOD1(EnqueueJobTaskSource, - bool(scoped_refptr<JobTaskSource> task_source)); - MOCK_CONST_METHOD1(IsRunningPoolWithTraits, bool(const TaskTraits& traits)); - MOCK_METHOD2(UpdatePriority, - void(scoped_refptr<TaskSource> task_source, - TaskPriority priority)); -}; - -class ThreadPoolJobTaskSourceTest : public testing::Test { - protected: - testing::StrictMock<MockPooledTaskRunnerDelegate> - pooled_task_runner_delegate_; -}; - // Verifies the normal flow of running 2 tasks one after the other. -TEST_F(ThreadPoolJobTaskSourceTest, RunTasks) { +TEST(ThreadPoolJobTaskSourceTest, RunTasks) { auto job_task = base::MakeRefCounted<test::MockJobTask>( DoNothing(), /* num_tasks_to_run */ 2); scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_); + FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT}); auto registered_task_source = RegisteredTaskSource::CreateForTesting(task_source); @@ -80,11 +55,11 @@ // Verifies that a job task source doesn't allow any new RunStatus after Clear() // is called. -TEST_F(ThreadPoolJobTaskSourceTest, Clear) { +TEST(ThreadPoolJobTaskSourceTest, Clear) { auto job_task = base::MakeRefCounted<test::MockJobTask>( DoNothing(), /* num_tasks_to_run */ 5); scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_); + FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT}); EXPECT_EQ(5U, task_source->GetRemainingConcurrency()); auto registered_task_source_a = @@ -141,11 +116,11 @@ } // Verifies that multiple tasks can run in parallel up to |max_concurrency|. -TEST_F(ThreadPoolJobTaskSourceTest, RunTasksInParallel) { +TEST(ThreadPoolJobTaskSourceTest, RunTasksInParallel) { auto job_task = base::MakeRefCounted<test::MockJobTask>( DoNothing(), /* num_tasks_to_run */ 2); scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_); + FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT}); auto registered_task_source_a = RegisteredTaskSource::CreateForTesting(task_source); @@ -183,138 +158,12 @@ EXPECT_FALSE(registered_task_source_c.DidProcessTask()); } -// Verifies that a call to NotifyConcurrencyIncrease() calls the delegate -// and allows to run additional tasks. -TEST_F(ThreadPoolJobTaskSourceTest, NotifyConcurrencyIncrease) { - auto job_task = base::MakeRefCounted<test::MockJobTask>( - DoNothing(), /* num_tasks_to_run */ 1); - scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_); - - auto registered_task_source_a = - RegisteredTaskSource::CreateForTesting(task_source); - EXPECT_EQ(registered_task_source_a.WillRunTask(), - TaskSource::RunStatus::kAllowedSaturated); - auto task_a = registered_task_source_a.TakeTask(); - EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(), - TaskSource::RunStatus::kDisallowed); - - job_task->SetNumTasksToRun(2); - EXPECT_CALL(pooled_task_runner_delegate_, EnqueueJobTaskSource(_)).Times(1); - task_source->NotifyConcurrencyIncrease(); - - auto registered_task_source_b = - RegisteredTaskSource::CreateForTesting(task_source); - // WillRunTask() should return a valid RunStatus because max concurrency was - // increased to 2. - EXPECT_EQ(registered_task_source_b.WillRunTask(), - TaskSource::RunStatus::kAllowedSaturated); - auto task_b = registered_task_source_b.TakeTask(); - EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(), - TaskSource::RunStatus::kDisallowed); - - std::move(task_a->task).Run(); - EXPECT_FALSE(registered_task_source_a.DidProcessTask()); - - std::move(task_b->task).Run(); - EXPECT_FALSE(registered_task_source_b.DidProcessTask()); -} - -// Verifies that ShouldYield() calls the delegate. -TEST_F(ThreadPoolJobTaskSourceTest, ShouldYield) { - auto job_task = base::MakeRefCounted<test::MockJobTask>( - BindLambdaForTesting([](experimental::JobDelegate* delegate) { - // As set up below, the mock will return false once and true the second - // time. - EXPECT_FALSE(delegate->ShouldYield()); - EXPECT_TRUE(delegate->ShouldYield()); - }), - /* num_tasks_to_run */ 1); - scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_); - - auto registered_task_source = - RegisteredTaskSource::CreateForTesting(task_source); - ASSERT_EQ(registered_task_source.WillRunTask(), - TaskSource::RunStatus::kAllowedSaturated); - - auto task = registered_task_source.TakeTask(); - - EXPECT_CALL(pooled_task_runner_delegate_, ShouldYield(_)) - .Times(2) - .WillOnce(Return(false)) - .WillOnce(Return(true)); - - std::move(task->task).Run(); - EXPECT_FALSE(registered_task_source.DidProcessTask()); -} - -// Verifies that max concurrency is allowed to stagnate when ShouldYield returns -// true. -TEST_F(ThreadPoolJobTaskSourceTest, MaxConcurrencyStagnateIfShouldYield) { - scoped_refptr<JobTaskSource> task_source = - base::MakeRefCounted<JobTaskSource>( - FROM_HERE, ThreadPool(), - BindRepeating([](experimental::JobDelegate* delegate) { - // As set up below, the mock will return true once. - ASSERT_TRUE(delegate->ShouldYield()); - }), - BindRepeating([]() -> size_t { - return 1; // max concurrency is always 1. - }), - &pooled_task_runner_delegate_); - - EXPECT_CALL(pooled_task_runner_delegate_, ShouldYield(_)) - .WillOnce(Return(true)); - - auto registered_task_source = - RegisteredTaskSource::CreateForTesting(task_source); - ASSERT_EQ(registered_task_source.WillRunTask(), - TaskSource::RunStatus::kAllowedSaturated); - auto task = registered_task_source.TakeTask(); - - // Running the task should not fail even though max concurrency remained at 1, - // since ShouldYield() returned true. - std::move(task->task).Run(); - registered_task_source.DidProcessTask(); -} - -// Verifies that a missing call to NotifyConcurrencyIncrease() causes a DCHECK -// death after a timeout. -TEST_F(ThreadPoolJobTaskSourceTest, InvalidConcurrency) { - testing::FLAGS_gtest_death_test_style = "threadsafe"; - - scoped_refptr<test::MockJobTask> job_task; - job_task = base::MakeRefCounted<test::MockJobTask>( - BindLambdaForTesting([&](experimental::JobDelegate* delegate) { - EXPECT_FALSE(delegate->ShouldYield()); - job_task->SetNumTasksToRun(2); - EXPECT_FALSE(delegate->ShouldYield()); - - // After returning, a DCHECK should trigger because we never called - // NotifyConcurrencyIncrease(). - }), - /* num_tasks_to_run */ 1); - scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_); - - auto registered_task_source = - RegisteredTaskSource::CreateForTesting(task_source); - ASSERT_EQ(registered_task_source.WillRunTask(), - TaskSource::RunStatus::kAllowedSaturated); - auto task = registered_task_source.TakeTask(); - - EXPECT_DCHECK_DEATH(std::move(task->task).Run()); - - registered_task_source.DidProcessTask(); -} - -TEST_F(ThreadPoolJobTaskSourceTest, InvalidTakeTask) { +TEST(ThreadPoolJobTaskSourceTest, InvalidTakeTask) { auto job_task = base::MakeRefCounted<test::MockJobTask>(DoNothing(), /* num_tasks_to_run */ 1); scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_); + FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT}); auto registered_task_source_a = RegisteredTaskSource::CreateForTesting(task_source); @@ -333,12 +182,12 @@ registered_task_source_a.DidProcessTask(); } -TEST_F(ThreadPoolJobTaskSourceTest, InvalidDidProcessTask) { +TEST(ThreadPoolJobTaskSourceTest, InvalidDidProcessTask) { auto job_task = base::MakeRefCounted<test::MockJobTask>(DoNothing(), /* num_tasks_to_run */ 1); scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_); + FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT}); auto registered_task_source = RegisteredTaskSource::CreateForTesting(task_source);
diff --git a/base/task/thread_pool/pooled_task_runner_delegate.h b/base/task/thread_pool/pooled_task_runner_delegate.h index f6687bd..46dbe39 100644 --- a/base/task/thread_pool/pooled_task_runner_delegate.h +++ b/base/task/thread_pool/pooled_task_runner_delegate.h
@@ -27,11 +27,6 @@ // outlives the ThreadPoolInstance that created it. static bool Exists(); - // Returns true if |task_source| currently running must return ASAP. - // Thread-safe but may return an outdated result (if a task unnecessarily - // yields due to this, it will simply be re-scheduled). - virtual bool ShouldYield(TaskSource* task_source) const = 0; - // Invoked when a |task| is posted to the PooledParallelTaskRunner or // PooledSequencedTaskRunner. The implementation must post |task| to // |sequence| within the appropriate priority queue, depending on |sequence| @@ -41,8 +36,7 @@ // Invoked when a task is posted as a Job. The implementation must add // |task_source| to the appropriate priority queue, depending on |task_source| - // traits, if it's not there already. Returns true if task source was - // successfully enqueued or was already enqueued. + // traits. Returns true if task source was successfully enqueued. virtual bool EnqueueJobTaskSource( scoped_refptr<JobTaskSource> task_source) = 0;
diff --git a/base/task/thread_pool/task_source.cc b/base/task/thread_pool/task_source.cc index 271988c..1cf36d5 100644 --- a/base/task/thread_pool/task_source.cc +++ b/base/task/thread_pool/task_source.cc
@@ -40,8 +40,6 @@ if (FeatureList::IsEnabled(kAllTasksUserBlocking)) return; task_source_->traits_.UpdatePriority(priority); - task_source_->priority_racy_.store(task_source_->traits_.priority(), - std::memory_order_relaxed); } void TaskSource::SetHeapHandle(const HeapHandle& handle) { @@ -56,7 +54,6 @@ TaskRunner* task_runner, TaskSourceExecutionMode execution_mode) : traits_(traits), - priority_racy_(traits.priority()), task_runner_(task_runner), execution_mode_(execution_mode) { DCHECK(task_runner_ ||
diff --git a/base/task/thread_pool/task_source.h b/base/task/thread_pool/task_source.h index e56b42e..df8bebe 100644 --- a/base/task/thread_pool/task_source.h +++ b/base/task/thread_pool/task_source.h
@@ -160,14 +160,6 @@ TaskShutdownBehavior shutdown_behavior() const { return traits_.shutdown_behavior(); } - // Returns a racy priority of the TaskSource. Can be accessed without a - // Transaction but may return an outdated result. - TaskPriority priority_racy() const { - return priority_racy_.load(std::memory_order_relaxed); - } - // Returns the thread policy of the TaskSource. Can be accessed without a - // Transaction because it is never mutated. - ThreadPolicy thread_policy() const { return traits_.thread_policy(); } // A reference to TaskRunner is only retained between PushTask() and when // DidProcessTask() returns false, guaranteeing it is safe to dereference this @@ -201,9 +193,6 @@ // The TaskTraits of all Tasks in the TaskSource. TaskTraits traits_; - // The cached priority for atomic access. - std::atomic<TaskPriority> priority_racy_; - // Synchronizes access to all members. mutable CheckedLock lock_{UniversalPredecessor()};
diff --git a/base/task/thread_pool/test_utils.cc b/base/task/thread_pool/test_utils.cc index 02ae793..3d7a2bb 100644 --- a/base/task/thread_pool/test_utils.cc +++ b/base/task/thread_pool/test_utils.cc
@@ -56,8 +56,8 @@ return false; auto job_task = base::MakeRefCounted<MockJobTask>(std::move(closure)); - scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - from_here, traits_, pooled_task_runner_delegate_); + scoped_refptr<JobTaskSource> task_source = + job_task->GetJobTaskSource(from_here, traits_); return pooled_task_runner_delegate_->EnqueueJobTaskSource( std::move(task_source)); } @@ -217,10 +217,6 @@ } } -bool MockPooledTaskRunnerDelegate::ShouldYield(TaskSource* task_source) const { - return thread_group_->ShouldYield(task_source->priority_racy()); -} - bool MockPooledTaskRunnerDelegate::EnqueueJobTaskSource( scoped_refptr<JobTaskSource> task_source) { // |thread_group_| must be initialized with SetThreadGroup() before @@ -281,6 +277,8 @@ } void MockJobTask::Run(experimental::JobDelegate* delegate) { + if (delegate->ShouldYield()) + return; worker_task_.Run(delegate); size_t before = remaining_num_tasks_to_run_.fetch_sub(1); DCHECK_GT(before, 0U); @@ -288,12 +286,10 @@ scoped_refptr<JobTaskSource> MockJobTask::GetJobTaskSource( const Location& from_here, - const TaskTraits& traits, - PooledTaskRunnerDelegate* delegate) { + const TaskTraits& traits) { return MakeRefCounted<JobTaskSource>( from_here, traits, base::BindRepeating(&test::MockJobTask::Run, this), - base::BindRepeating(&test::MockJobTask::GetMaxConcurrency, this), - delegate); + base::BindRepeating(&test::MockJobTask::GetMaxConcurrency, this)); } RegisteredTaskSource QueueAndRunTaskSource(
diff --git a/base/task/thread_pool/test_utils.h b/base/task/thread_pool/test_utils.h index cc378fc..554c205 100644 --- a/base/task/thread_pool/test_utils.h +++ b/base/task/thread_pool/test_utils.h
@@ -62,7 +62,6 @@ bool PostTaskWithSequence(Task task, scoped_refptr<Sequence> sequence) override; bool EnqueueJobTaskSource(scoped_refptr<JobTaskSource> task_source) override; - bool ShouldYield(TaskSource* task_source) const override; bool IsRunningPoolWithTraits(const TaskTraits& traits) const override; void UpdatePriority(scoped_refptr<TaskSource> task_source, TaskPriority priority) override; @@ -82,6 +81,8 @@ class MockJobTask : public base::RefCountedThreadSafe<MockJobTask> { public: // Gives |worker_task| to requesting workers |num_tasks_to_run| times. + // ShouldYield() is automatically called on JobDelegate before running + // |worker_task| so that DoNothing() may be passed. MockJobTask( base::RepeatingCallback<void(experimental::JobDelegate*)> worker_task, size_t num_tasks_to_run); @@ -98,10 +99,8 @@ size_t GetMaxConcurrency() const; void Run(experimental::JobDelegate* delegate); - scoped_refptr<JobTaskSource> GetJobTaskSource( - const Location& from_here, - const TaskTraits& traits, - PooledTaskRunnerDelegate* delegate); + scoped_refptr<JobTaskSource> GetJobTaskSource(const Location& from_here, + const TaskTraits& traits); private: friend class base::RefCountedThreadSafe<MockJobTask>;
diff --git a/base/task/thread_pool/thread_group_impl_unittest.cc b/base/task/thread_pool/thread_group_impl_unittest.cc index 50baf9ab..771b3ff 100644 --- a/base/task/thread_pool/thread_group_impl_unittest.cc +++ b/base/task/thread_pool/thread_group_impl_unittest.cc
@@ -311,8 +311,7 @@ }), /* num_tasks_to_run */ kMaxTasks); scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, {ThreadPool(), TaskPriority::USER_VISIBLE}, - &mock_pooled_task_runner_delegate_); + FROM_HERE, {ThreadPool(), TaskPriority::USER_VISIBLE}); auto registered_task_source = task_tracker_.RegisterTaskSource(task_source); ASSERT_TRUE(registered_task_source);
diff --git a/base/task/thread_pool/thread_group_unittest.cc b/base/task/thread_pool/thread_group_unittest.cc index cb4481c..4bb81dc 100644 --- a/base/task/thread_pool/thread_group_unittest.cc +++ b/base/task/thread_pool/thread_group_unittest.cc
@@ -596,8 +596,8 @@ test::WaitWithoutBlockingObserver(&threads_continue); }), /* num_tasks_to_run */ kMaxTasks); - scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &mock_pooled_task_runner_delegate_); + scoped_refptr<JobTaskSource> task_source = + job_task->GetJobTaskSource(FROM_HERE, {ThreadPool()}); auto registered_task_source = task_tracker_.RegisterTaskSource(std::move(task_source)); @@ -614,95 +614,6 @@ task_tracker_.FlushForTesting(); } -// Verify that tasks from a JobTaskSource run at the intended concurrency. -TEST_P(ThreadGroupTest, ScheduleJobTaskSourceMultipleTime) { - StartThreadGroup(); - - WaitableEvent thread_running; - WaitableEvent thread_continue; - auto job_task = base::MakeRefCounted<test::MockJobTask>( - BindLambdaForTesting( - [&thread_running, &thread_continue](experimental::JobDelegate*) { - DCHECK(!thread_running.IsSignaled()); - thread_running.Signal(); - test::WaitWithoutBlockingObserver(&thread_continue); - }), - /* num_tasks_to_run */ 1); - scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &mock_pooled_task_runner_delegate_); - - thread_group_->PushTaskSourceAndWakeUpWorkers( - TransactionWithRegisteredTaskSource::FromTaskSource( - task_tracker_.RegisterTaskSource(task_source))); - - // Enqueuing the task source again shouldn't affect the number of time it's - // run. - thread_group_->PushTaskSourceAndWakeUpWorkers( - TransactionWithRegisteredTaskSource::FromTaskSource( - task_tracker_.RegisterTaskSource(task_source))); - - thread_running.Wait(); - thread_continue.Signal(); - - // Once the worker task ran, enqueuing the task source has no effect. - thread_group_->PushTaskSourceAndWakeUpWorkers( - TransactionWithRegisteredTaskSource::FromTaskSource( - task_tracker_.RegisterTaskSource(task_source))); - - // Flush the task tracker to be sure that no local variables are accessed by - // tasks after the end of the scope. - task_tracker_.FlushForTesting(); -} - -// Verify that calling JobTaskSource::NotifyConcurrencyIncrease() (re-)schedule -// tasks with the intended concurrency. -TEST_P(ThreadGroupTest, JobTaskSourceConcurrencyIncrease) { - StartThreadGroup(); - - WaitableEvent threads_running_a; - WaitableEvent threads_continue; - - // Initially schedule half the tasks. - RepeatingClosure threads_running_barrier = BarrierClosure( - kMaxTasks / 2, - BindOnce(&WaitableEvent::Signal, Unretained(&threads_running_a))); - - auto job_state = base::MakeRefCounted<test::MockJobTask>( - BindLambdaForTesting([&threads_running_barrier, - &threads_continue](experimental::JobDelegate*) { - threads_running_barrier.Run(); - test::WaitWithoutBlockingObserver(&threads_continue); - }), - /* num_tasks_to_run */ kMaxTasks / 2); - auto task_source = job_state->GetJobTaskSource( - FROM_HERE, ThreadPool(), &mock_pooled_task_runner_delegate_); - - auto registered_task_source = task_tracker_.RegisterTaskSource(task_source); - EXPECT_TRUE(registered_task_source); - thread_group_->PushTaskSourceAndWakeUpWorkers( - TransactionWithRegisteredTaskSource::FromTaskSource( - std::move(registered_task_source))); - - threads_running_a.Wait(); - // Reset |threads_running_barrier| for the remaining tasks. - WaitableEvent threads_running_b; - threads_running_barrier = BarrierClosure( - kMaxTasks / 2, - BindOnce(&WaitableEvent::Signal, Unretained(&threads_running_b))); - job_state->SetNumTasksToRun(kMaxTasks); - - // Unblocks tasks to let them racily wait for NotifyConcurrencyIncrease() to - // be called. - threads_continue.Signal(); - task_source->NotifyConcurrencyIncrease(); - // Wait for the remaining tasks. This should not block forever. - threads_running_b.Wait(); - - // Flush the task tracker to be sure that no local variables are accessed by - // tasks after the end of the scope. - task_tracker_.FlushForTesting(); -} - // Verify that a JobTaskSource that becomes empty while in the queue eventually // gets discarded. TEST_P(ThreadGroupTest, ScheduleEmptyJobTaskSource) { @@ -713,8 +624,8 @@ auto job_task = base::MakeRefCounted<test::MockJobTask>( BindRepeating([](experimental::JobDelegate*) { ShouldNotRun(); }), /* num_tasks_to_run */ 1); - scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, ThreadPool(), &mock_pooled_task_runner_delegate_); + scoped_refptr<JobTaskSource> task_source = + job_task->GetJobTaskSource(FROM_HERE, {ThreadPool()}); auto registered_task_source = task_tracker_.RegisterTaskSource(std::move(task_source)); @@ -763,8 +674,7 @@ }), /* num_tasks_to_run */ kMaxTasks); scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT}, - &mock_pooled_task_runner_delegate_); + FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT}); auto registered_task_source = task_tracker_.RegisterTaskSource(task_source); EXPECT_TRUE(registered_task_source);
diff --git a/base/task/thread_pool/thread_pool_impl.cc b/base/task/thread_pool/thread_pool_impl.cc index fcb783c..6953de1 100644 --- a/base/task/thread_pool/thread_pool_impl.cc +++ b/base/task/thread_pool/thread_pool_impl.cc
@@ -18,7 +18,6 @@ #include "base/metrics/field_trial_params.h" #include "base/stl_util.h" #include "base/strings/string_util.h" -#include "base/task/scoped_set_task_priority_for_current_thread.h" #include "base/task/task_features.h" #include "base/task/thread_pool/pooled_parallel_task_runner.h" #include "base/task/thread_pool/pooled_sequenced_task_runner.h" @@ -397,19 +396,6 @@ return true; } -bool ThreadPoolImpl::ShouldYield(TaskSource* task_source) const { - const TaskPriority priority = task_source->priority_racy(); - auto* const thread_group = GetThreadGroupForTraits( - {ThreadPool(), priority, task_source->thread_policy()}); - // A task whose priority changed and is now running in the wrong thread group - // should yield so it's rescheduled in the right one. - if (!thread_group->IsBoundToCurrentThread()) - return true; - return GetThreadGroupForTraits( - {ThreadPool(), priority, task_source->thread_policy()}) - ->ShouldYield(priority); -} - bool ThreadPoolImpl::EnqueueJobTaskSource( scoped_refptr<JobTaskSource> task_source) { auto registered_task_source =
diff --git a/base/task/thread_pool/thread_pool_impl.h b/base/task/thread_pool/thread_pool_impl.h index d66f0a6..75d72f05 100644 --- a/base/task/thread_pool/thread_pool_impl.h +++ b/base/task/thread_pool/thread_pool_impl.h
@@ -103,8 +103,6 @@ // PooledTaskRunnerDelegate: bool EnqueueJobTaskSource(scoped_refptr<JobTaskSource> task_source) override; - void UpdatePriority(scoped_refptr<TaskSource> task_source, - TaskPriority priority) override; // Returns the TimeTicks of the next task scheduled on ThreadPool (Now() if // immediate, nullopt if none). This is thread-safe, i.e., it's safe if tasks @@ -141,7 +139,8 @@ bool PostTaskWithSequence(Task task, scoped_refptr<Sequence> sequence) override; bool IsRunningPoolWithTraits(const TaskTraits& traits) const override; - bool ShouldYield(TaskSource* task_source) const override; + void UpdatePriority(scoped_refptr<TaskSource> task_source, + TaskPriority priority) override; const std::unique_ptr<TaskTrackerImpl> task_tracker_; std::unique_ptr<Thread> service_thread_;
diff --git a/base/task/thread_pool/thread_pool_impl_unittest.cc b/base/task/thread_pool/thread_pool_impl_unittest.cc index 7e1cb29..337eb73d 100644 --- a/base/task/thread_pool/thread_pool_impl_unittest.cc +++ b/base/task/thread_pool/thread_pool_impl_unittest.cc
@@ -1087,47 +1087,12 @@ }), /* num_tasks_to_run */ 1); scoped_refptr<JobTaskSource> task_source = - job_task->GetJobTaskSource(FROM_HERE, ThreadPool(), thread_pool_.get()); + job_task->GetJobTaskSource(FROM_HERE, {ThreadPool()}); thread_pool_->EnqueueJobTaskSource(task_source); threads_running.Wait(); } -// Verify that calling ShouldYield() returns true for a job task source that -// needs to change thread group because of a priority update. -TEST_P(ThreadPoolImplTest, ThreadGroupChangeShouldYield) { - StartThreadPool(); - - WaitableEvent threads_running; - WaitableEvent threads_continue; - - auto job_task = base::MakeRefCounted<test::MockJobTask>( - BindLambdaForTesting([&threads_running, &threads_continue]( - experimental::JobDelegate* delegate) { - EXPECT_FALSE(delegate->ShouldYield()); - - threads_running.Signal(); - test::WaitWithoutBlockingObserver(&threads_continue); - - // The task source needs to yield if background thread groups exist. - EXPECT_EQ(delegate->ShouldYield(), - CanUseBackgroundPriorityForWorkerThread()); - }), - /* num_tasks_to_run */ 1); - scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource( - FROM_HERE, {ThreadPool(), TaskPriority::USER_VISIBLE}, - thread_pool_.get()); - - thread_pool_->EnqueueJobTaskSource(task_source); - threads_running.Wait(); - thread_pool_->UpdatePriority(task_source, TaskPriority::BEST_EFFORT); - threads_continue.Signal(); - - // Flush the task tracker to be sure that no local variables are accessed by - // tasks after the end of the scope. - thread_pool_->FlushForTesting(); -} - namespace { class MustBeDestroyed {
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h index 98e316ac..09e7d73 100644 --- a/base/threading/thread_restrictions.h +++ b/base/threading/thread_restrictions.h
@@ -275,7 +275,6 @@ } namespace internal { -class JobTaskSource; class TaskTracker; } @@ -451,7 +450,6 @@ friend class audio::OutputDevice; friend class base::sequence_manager::internal::TaskQueueImpl; friend class base::FileDescriptorWatcher; - friend class base::internal::JobTaskSource; friend class base::MessageLoopImpl; friend class base::ScopedAllowThreadRecallForStackSamplingProfiler; friend class base::StackSamplingProfiler;
diff --git a/chrome/app/file_pre_reader_win.cc b/base/win/file_pre_reader.cc similarity index 76% rename from chrome/app/file_pre_reader_win.cc rename to base/win/file_pre_reader.cc index b3453009..581745f 100644 --- a/chrome/app/file_pre_reader_win.cc +++ b/base/win/file_pre_reader.cc
@@ -2,16 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/app/file_pre_reader_win.h" +#include "base/win/file_pre_reader.h" #include <windows.h> #include <memoryapi.h> // NOLINT(build/include_order) #include "base/files/file.h" +#include "base/files/file_path.h" #include "base/files/memory_mapped_file.h" -void PreReadFile(const base::FilePath& file_path) { +namespace base { +namespace win { + +void PreReadFile(const FilePath& file_path, bool is_executable) { // On Win8 and higher use ::PrefetchVirtualMemory(). This is better than // a simple data file read, more from a RAM perspective than CPU. This is // because reading the file as data results in double mapping to @@ -31,8 +35,8 @@ constexpr DWORD kStepSize = 1024 * 1024; - base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ | - base::File::FLAG_SEQUENTIAL_SCAN); + File file(file_path, + File::FLAG_OPEN | File::FLAG_READ | File::FLAG_SEQUENTIAL_SCAN); if (!file.IsValid()) return; @@ -51,9 +55,12 @@ // loadlibrary the file while we are doing the mapping and prefetching or // the process will get a private copy of the DLL via COW. - base::MemoryMappedFile mapped_file; - if (mapped_file.Initialize(file_path, - base::MemoryMappedFile::READ_CODE_IMAGE)) { + MemoryMappedFile mapped_file; + MemoryMappedFile::Access access = is_executable + ? MemoryMappedFile::READ_CODE_IMAGE + : MemoryMappedFile::READ_ONLY; + + if (mapped_file.Initialize(file_path, access)) { _WIN32_MEMORY_RANGE_ENTRY address_range = {mapped_file.data(), mapped_file.length()}; @@ -64,3 +71,6 @@ } } } + +} // namespace win +} // namespace base \ No newline at end of file
diff --git a/base/win/file_pre_reader.h b/base/win/file_pre_reader.h new file mode 100644 index 0000000..72fefe4 --- /dev/null +++ b/base/win/file_pre_reader.h
@@ -0,0 +1,28 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file defines a function to pre-read a file in order to avoid touching +// the disk when it is subsequently used. + +#include "base/base_export.h" + +#ifndef BASE_WIN_FILE_PRE_READER_H_ +#define BASE_WIN_FILE_PRE_READER_H_ + +namespace base { + +class FilePath; + +namespace win { + +// Pre-reads |file_path| to avoid touching the disk when the file is actually +// used. |is_executable| specifies whether the file is to be prefetched as +// executable code or as data. Windows treats the file backed pages in RAM +// differently and specifying the wrong one results in two copies in RAM. +BASE_EXPORT void PreReadFile(const FilePath& file_path, bool is_executable); + +} // namespace win +} // namespace base + +#endif // BASE_WIN_FILE_PRE_READER_H_
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index e6b3730..210a876d 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8903989905342745168 \ No newline at end of file +8903962831524890912 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 14e8590..a684367 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8903994421773374304 \ No newline at end of file +8903961994040181600 \ No newline at end of file
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index a9814f1..dd3a0986 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -195,7 +195,6 @@ ":chrome_dll", ":chrome_exe_version", ":copy_first_run", - ":file_pre_reader", ":visual_elements_resources", "//base", "//chrome/app/version_assembly:chrome_exe_manifest", @@ -1493,16 +1492,6 @@ ] output = "$target_gen_dir/other_version.rc" } - - source_set("file_pre_reader") { - sources = [ - "app/file_pre_reader_win.cc", - "app/file_pre_reader_win.h", - ] - deps = [ - "//base", - ] - } } copy("visual_elements_resources") {
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryIPHUtils.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryIPHUtils.java index 553ce46..7f3b425 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryIPHUtils.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryIPHUtils.java
@@ -14,6 +14,7 @@ import org.chromium.components.feature_engagement.EventConstants; import org.chromium.components.feature_engagement.FeatureConstants; import org.chromium.components.feature_engagement.Tracker; +import org.chromium.ui.widget.ChipView; import org.chromium.ui.widget.ViewRectProvider; /** @@ -51,7 +52,7 @@ * @param feature A String identifying the IPH feature and its appropriate help text. * @param view The {@link View} providing context and the Rect to which the bubble will point. */ - static void showHelpBubble(String feature, View view) { + static void showHelpBubble(String feature, ChipView view) { final Tracker tracker = TrackerFactory.getTrackerForProfile(Profile.getLastUsedProfile()); if (!tracker.isInitialized()) return; if (!tracker.shouldTriggerHelpUI(feature)) return; // This call records the IPH intent. @@ -61,7 +62,13 @@ helpText, true, new ViewRectProvider(view), R.drawable.ic_chrome); helpBubble.setDismissOnTouchInteraction(true); helpBubble.show(); - helpBubble.addOnDismissListener(() -> tracker.dismissed(feature)); + // To emphasize which chip is pointed to, set selected to true for the built-in highlight. + // Prefer ViewHighlighter for views without a LayerDrawable background. + view.setSelected(true); + helpBubble.addOnDismissListener(() -> { + tracker.dismissed(feature); + view.setSelected(false); + }); } /**
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java index 68ac271..282af258 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
@@ -6,8 +6,11 @@ import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.ViewMatchers.assertThat; import static android.support.test.espresso.matcher.ViewMatchers.isRoot; +import static android.support.test.espresso.matcher.ViewMatchers.isSelected; +import static android.support.test.espresso.matcher.ViewMatchers.withChild; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.is; @@ -246,11 +249,13 @@ onView(isRoot()).check((root, e) -> waitForView((ViewGroup) root, withText("Johnathan"))); waitForHelpBubble(withText(R.string.iph_keyboard_accessory_fill_password)); + onView(withChild(withText("Johnathan"))).check(matches(isSelected())); onView(withText("Johnathan")).perform(click()); assertThat(tracker.wasDismissed(), is(true)); assertThat(tracker.getLastEmittedEvent(), is(EventConstants.KEYBOARD_ACCESSORY_PASSWORD_AUTOFILLED)); + onView(withChild(withText("Johnathan"))).check(matches(not(isSelected()))); } @Test
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn index 1287a31..0959d58 100644 --- a/chrome/android/features/tab_ui/BUILD.gn +++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -130,6 +130,10 @@ "java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java", + "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProvider.java", + "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProvider.java", + "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java", + "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java", ] deps = [
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProvider.java new file mode 100644 index 0000000..fffd8f0 --- /dev/null +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProvider.java
@@ -0,0 +1,41 @@ +// Copyright 2019 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.tasks.tab_management.suggestions; + +import org.chromium.chrome.browser.ChromeFeatureList; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * Provider which returns tabs which have not been used beyond a time threshold. + */ +public class StaleTabSuggestionProvider implements TabSuggestionProvider { + private static final int DEFAULT_THRESHOLD = (int) TimeUnit.DAYS.toMillis(1); + + @Override + public List<TabSuggestion> suggest(TabContext tabContext) { + if (tabContext == null || tabContext.getUngroupedTabs() == null + || tabContext.getUngroupedTabs().size() < 1) { + return null; + } + + long staleThreshold = ChromeFeatureList.getFieldTrialParamByFeatureAsInt( + ChromeFeatureList.CLOSE_TAB_SUGGESTIONS_STALE, + "close_tab_suggestions_stale_time_ms", DEFAULT_THRESHOLD); + + long now = System.currentTimeMillis(); + List<TabContext.TabInfo> staleTabs = new ArrayList<>(); + for (TabContext.TabInfo tab : tabContext.getUngroupedTabs()) { + if (now - tab.timestampMillis > staleThreshold) { + staleTabs.add(tab); + } + } + return Arrays.asList(new TabSuggestion(staleTabs, TabSuggestion.TabSuggestionAction.CLOSE, + TabSuggestionsRanker.SuggestionProviders.STALE_TABS_SUGGESTION_PROVIDER)); + } +}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java new file mode 100644 index 0000000..2138818 --- /dev/null +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java
@@ -0,0 +1,206 @@ +// Copyright 2019 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.tasks.tab_management.suggestions; + +import android.text.TextUtils; + +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tabmodel.TabModelFilter; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.content_public.browser.NavigationEntry; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Represents a snapshot of the current tabs and tab groups. + */ +public class TabContext { + /** + * Holds basic information about a tab group. + */ + public static class TabGroupInfo { + public final int rootId; + public final List<TabInfo> tabs; + + public TabGroupInfo(int rootId, List<TabInfo> tabs) { + this.rootId = rootId; + this.tabs = Collections.unmodifiableList(tabs); + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + if (other == null) return false; + if (other instanceof TabGroupInfo) { + TabGroupInfo otherGroupInfo = (TabGroupInfo) other; + return rootId == otherGroupInfo.rootId && tabs == null + ? otherGroupInfo.tabs == null + : tabs.equals(otherGroupInfo.tabs); + } + return false; + } + + @Override + public int hashCode() { + int result = 31 * (tabs == null ? 0 : tabs.hashCode()); + result = 31 * result + rootId; + return result; + } + } + + /** + * Holds basic information about a tab. + */ + public static class TabInfo implements Comparable<TabInfo> { + // equals() and hashCode() only include url and id + public final String url; + public final String referrerUrl; + public final long timestampMillis; + public final int id; + public final String title; + public final String originalUrl; + + /** + * Constructs a new TabInfo object + */ + protected TabInfo(int id, String title, String url, String originalUrl, String referrerUrl, + long timestampMillis) { + this.id = id; + this.title = title; + this.url = url; + this.originalUrl = originalUrl; + this.referrerUrl = referrerUrl; + this.timestampMillis = timestampMillis; + } + + /** + * Creates a new TabInfo object from {@link Tab} + */ + public static TabInfo createFromTab(Tab tab) { + String referrerUrl = getReferrerUrlFromTab(tab); + return new TabInfo(tab.getId(), tab.getTitle(), tab.getUrl(), tab.getOriginalUrl(), + referrerUrl != null ? referrerUrl : "", tab.getTimestampMillis()); + } + + private static String getReferrerUrlFromTab(Tab tab) { + if (tab.getWebContents() == null) { + return null; + } + if (tab.getWebContents().getNavigationController() == null) { + return null; + } + int lastCommittedIndex = + tab.getWebContents().getNavigationController().getLastCommittedEntryIndex(); + NavigationEntry lastCommittedEntry = + tab.getWebContents().getNavigationController().getEntryAtIndex( + lastCommittedIndex); + if (lastCommittedEntry == null) { + return null; + } + return lastCommittedEntry.getReferrerUrl(); + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + if (other == null) return false; + if (other instanceof TabInfo) { + TabInfo otherTabInfo = (TabInfo) other; + return id == otherTabInfo.id && TextUtils.equals(url, otherTabInfo.url); + } + return false; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + id; + result = 31 * result + url == null ? 0 : url.hashCode(); + return result; + } + + @Override + public int compareTo(TabInfo other) { + return Integer.compare(id, other.id); + } + } + + private final List<TabInfo> mUngroupedTabs; + private final List<TabGroupInfo> mTabGroups; + + protected TabContext(List<TabInfo> ungroupedTabs, List<TabGroupInfo> groups) { + mUngroupedTabs = Collections.unmodifiableList(ungroupedTabs); + mTabGroups = Collections.unmodifiableList(groups); + } + + public List<TabInfo> getUngroupedTabs() { + return mUngroupedTabs; + } + + public List<TabGroupInfo> getTabGroups() { + return mTabGroups; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + if (other == null) return false; + if (other instanceof TabContext) { + TabContext otherTabContext = (TabContext) other; + return (mTabGroups == null ? otherTabContext.getTabGroups() == null + : mTabGroups.equals(otherTabContext.getTabGroups())) + && (mUngroupedTabs == null + ? otherTabContext.getUngroupedTabs() == null + : mUngroupedTabs.equals(otherTabContext.getUngroupedTabs())); + } + return false; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + (mTabGroups == null ? 0 : mTabGroups.hashCode()); + result = 31 * result + (mUngroupedTabs == null ? 0 : mUngroupedTabs.hashCode()); + return result; + } + + /** + * Creates an instance of TabContext based on the provided {@link TabModelSelector}. + * @param tabModelSelector TabModelSelector for which the TabContext will be derived + * @return an instance of TabContext + */ + public static TabContext createCurrentContext(TabModelSelector tabModelSelector) { + TabModelFilter tabModelFilter = + tabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(); + List<TabInfo> ungroupedTabs = new ArrayList<>(); + List<TabGroupInfo> existingGroups = new ArrayList<>(); + + // Examine each tab in the current model and either add it to the list of ungrouped tabs or + // add it to a group it belongs to. + for (int i = 0; i < tabModelFilter.getCount(); i++) { + Tab currentTab = tabModelFilter.getTabAt(i); + List<Tab> relatedTabs = tabModelFilter.getRelatedTabList(currentTab.getId()); + + if (relatedTabs != null && relatedTabs.size() > 1) { + existingGroups.add( + new TabGroupInfo(currentTab.getRootId(), createTabInfoList(relatedTabs))); + } else { + ungroupedTabs.add(TabInfo.createFromTab(currentTab)); + } + } + + return new TabContext(ungroupedTabs, existingGroups); + } + + private static List<TabInfo> createTabInfoList(List<Tab> tabs) { + List<TabInfo> tabInfoList = new ArrayList<>(); + for (Tab tab : tabs) { + tabInfoList.add(TabInfo.createFromTab(tab)); + } + return tabInfoList; + } +}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestion.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestion.java new file mode 100644 index 0000000..5a0124ac --- /dev/null +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestion.java
@@ -0,0 +1,81 @@ +// Copyright 2019 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.tasks.tab_management.suggestions; + +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collections; +import java.util.List; + +/** + * Represents the output of the {@link TabSuggestions} pipeline. + */ +public final class TabSuggestion { + /** Types of Suggestion Actions */ + @IntDef({TabSuggestion.TabSuggestionAction.GROUP, TabSuggestion.TabSuggestionAction.CLOSE}) + @Retention(RetentionPolicy.SOURCE) + public @interface TabSuggestionAction { + int GROUP = 0; + int CLOSE = 1; + } + + private final List<TabContext.TabInfo> mTabsInfo; + private final @TabSuggestionAction int mAction; + private final String mProviderName; + private final Integer mTabGroupId; + + public TabSuggestion(List<TabContext.TabInfo> tabsInfo, @TabSuggestionAction int action, + String providerName) { + this(tabsInfo, action, providerName, null); + } + + public TabSuggestion(List<TabContext.TabInfo> tabsInfo, @TabSuggestionAction int action, + String providerName, Integer tabGroupId) { + mTabsInfo = Collections.unmodifiableList(tabsInfo); + mAction = action; + mProviderName = providerName; + mTabGroupId = tabGroupId; + } + + /** + * Returns the list of the suggested tabs + */ + public List<TabContext.TabInfo> getTabsInfo() { + return mTabsInfo; + } + + /** + * Returns the suggested action + */ + public @TabSuggestionAction int getAction() { + return mAction; + } + + /** + * Returns the provider's name + */ + public String getProviderName() { + return mProviderName; + } + + /** + * Checks if the suggestion is for an existing group + * @return true if the suggestion updates an existing group + */ + public boolean hasExistingGroupId() { + return getExistingTabGroupId() != null; + } + + /** + * If the suggestion is for an existing group, this will return the group id. Call @{link + * hasExistingGroupId} before calling this getter. + * @return existing group Id + */ + public Integer getExistingTabGroupId() { + return mTabGroupId; + } +}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProvider.java new file mode 100644 index 0000000..22e6a8d --- /dev/null +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProvider.java
@@ -0,0 +1,13 @@ +// Copyright 2019 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.tasks.tab_management.suggestions; + +import java.util.List; + +/** + * Defines the contract between {@link TabSuggestionsFetcher} and all the client-side suggestion + * providers. + */ +public interface TabSuggestionProvider { List<TabSuggestion> suggest(TabContext tabContext); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java new file mode 100644 index 0000000..0e8bd24 --- /dev/null +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java
@@ -0,0 +1,19 @@ +// Copyright 2019 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.tasks.tab_management.suggestions; + +/** + * Encapsulates signals indicating how useful the suggestions from a suggestions + * provider are. Used for aggregating and determining which suggestions to use + */ +class TabSuggestionProviderConfiguration { + public final int score; + public final boolean isEnabled; + + TabSuggestionProviderConfiguration(int score, boolean isEnabled) { + this.score = score; + this.isEnabled = isEnabled; + } +}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java new file mode 100644 index 0000000..2180e27b --- /dev/null +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java
@@ -0,0 +1,58 @@ +// Copyright 2019 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.tasks.tab_management.suggestions; + +import android.support.annotation.StringDef; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Ranker which ranks all suggestions based on static rules. + */ +public final class TabSuggestionsRanker { + /** + * List of all known providers (server & client). + * TODO(crbug.com/970933) decouple server providers from client. + */ + @StringDef({SuggestionProviders.STALE_TABS_SUGGESTION_PROVIDER}) + public @interface SuggestionProviders { + String STALE_TABS_SUGGESTION_PROVIDER = "StaleTabSuggestionProvider"; + } + + /** + * Ranks suggestions based on the number of tabs first and the score of the provider in case of + * a tie. This logic is subject to change in the future. + * @param suggestions to be ranked + * @param providerConfigs per-provider configurations + * @return sorted suggestions list where first suggestion in the list is the most preferred + */ + public static List<TabSuggestion> getRankedSuggestions(List<TabSuggestion> suggestions, + Map<String, TabSuggestionProviderConfiguration> providerConfigs) { + if (suggestions.isEmpty()) { + return suggestions; + } + + Collections.sort(suggestions, (a, b) -> { + if (a == b) return 0; + + if (a.getTabsInfo().size() == b.getTabsInfo().size()) { + int aScore = providerConfigs.containsKey(a.getProviderName()) + ? providerConfigs.get(a.getProviderName()).score + : 0; + int bScore = providerConfigs.containsKey(b.getProviderName()) + ? providerConfigs.get(b.getProviderName()).score + : 0; + + return Integer.compare(bScore, aScore); + } + + return Integer.compare(b.getTabsInfo().size(), a.getTabsInfo().size()); + }); + + return suggestions; + } +}
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java new file mode 100644 index 0000000..551ec39 --- /dev/null +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java
@@ -0,0 +1,78 @@ +// Copyright 2019 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.tasks.tab_management.suggestions; + +import static org.mockito.Mockito.doReturn; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.test.util.browser.Features; +import org.chromium.testing.local.LocalRobolectricTestRunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * Tests the provider which identifies Tabs which have not been used in a long time + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class StaleTabSuggestionProviderTest { + @Rule + public TestRule mProcessor = new Features.JUnitProcessor(); + + @Mock + TabContext mTabContext; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + } + + /** + * Test identification of Tabs which have not been used in a long time (threshold set to 1 day) + * and recommend to close them + */ + @Test + @Feature({"StaleTabSuggestionProvider"}) + @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + "enable-features=" + ChromeFeatureList.CLOSE_TAB_SUGGESTIONS_STALE + "<FakeStudyName", + "force-fieldtrials=FakeStudyName/Enabled", + "force-fieldtrial-params=FakeStudyName.Enabled:" + + "close_tab_suggestions_stale_time_ms/86400000"}) + // 86400000 milliseconds = 1 day + public void + testIdentifyStaleTabs() throws Exception { + StaleTabSuggestionProvider staleSuggestionsProvider = new StaleTabSuggestionProvider(); + List<TabContext.TabInfo> tabInfos = new ArrayList<>(); + tabInfos.add(new TabContext.TabInfo(3, "mock_recent_title", "mock_recent_url", + "mock_recent_original_url", "mock_recent_url", + System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5))); + tabInfos.add(new TabContext.TabInfo(3, "mock_stale_title", "mock_stale_url", + "mock_stale_original_url", "mock_stale_referrer_url", + System.currentTimeMillis() - TimeUnit.DAYS.toMillis(2))); + doReturn(tabInfos).when(mTabContext).getUngroupedTabs(); + List<TabSuggestion> staleSuggestions = staleSuggestionsProvider.suggest(mTabContext); + Assert.assertTrue(staleSuggestions.size() == 1); + TabSuggestion staleSuggestion = staleSuggestions.get(0); + Assert.assertEquals("mock_stale_title", staleSuggestion.getTabsInfo().get(0).title); + Assert.assertEquals(TabSuggestion.TabSuggestionAction.CLOSE, staleSuggestion.getAction()); + Assert.assertEquals(TabSuggestionsRanker.SuggestionProviders.STALE_TABS_SUGGESTION_PROVIDER, + staleSuggestion.getProviderName()); + } +}
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java new file mode 100644 index 0000000..37a78c7b --- /dev/null +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java
@@ -0,0 +1,131 @@ +// Copyright 2019 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.tasks.tab_management.suggestions; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tabmodel.TabModelFilter; +import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.test.util.browser.Features; +import org.chromium.content_public.browser.NavigationController; +import org.chromium.content_public.browser.NavigationEntry; +import org.chromium.content_public.browser.WebContents; +import org.chromium.testing.local.LocalRobolectricTestRunner; + +import java.util.Arrays; +import java.util.List; + +/** + * Tests functionality related to TabContext + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class TabContextTests { + private static final int TAB_0_ID = 0; + private static final int RELATED_TAB_0_ID = 1; + private static final int RELATED_TAB_1_ID = 2; + private static final int LAST_COMMITTED_INDEX = 1; + + @Rule + public TestRule mProcessor = new Features.JUnitProcessor(); + + @Mock + private TabModelSelector mTabModelSelector; + + @Mock + private TabModelFilterProvider mTabModelFilterProvider; + + @Mock + private TabModelFilter mTabModelFilter; + + private static Tab sTab0 = mockTab(TAB_0_ID, 6, "mock_title_tab_0", "mock_url_tab_0", + "mock_original_url_tab_0", "mock_referrer_url_tab_0", 100); + private static Tab sRelatedTab0 = + mockTab(RELATED_TAB_0_ID, 6, "mock_title_related_tab_0", "mock_url_related_tab_0", + "mock_original_url_related_tab_0", "mock_referrer_url_related_tab_0", 200); + private static Tab sRelatedTab1 = + mockTab(RELATED_TAB_1_ID, 6, "mock_title_related_tab_1", "mock_url_related_tab_1", + "mock_original_url_related_tab_1", "mock_referrer_url_related_tab_1", 300); + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider(); + doReturn(mTabModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); + } + + private static Tab mockTab(int id, int rootId, String title, String url, String originalUrl, + String referrerUrl, long getTimestampMillis) { + Tab tab = mock(Tab.class); + doReturn(id).when(tab).getId(); + doReturn(rootId).when(tab).getRootId(); + doReturn(title).when(tab).getTitle(); + doReturn(url).when(tab).getUrl(); + doReturn(originalUrl).when(tab).getOriginalUrl(); + WebContents webContents = mock(WebContents.class); + doReturn(webContents).when(tab).getWebContents(); + NavigationController navigationController = mock(NavigationController.class); + doReturn(navigationController).when(webContents).getNavigationController(); + doReturn(LAST_COMMITTED_INDEX).when(navigationController).getLastCommittedEntryIndex(); + NavigationEntry navigationEntry = mock(NavigationEntry.class); + doReturn(navigationEntry) + .when(navigationController) + .getEntryAtIndex(eq(LAST_COMMITTED_INDEX)); + doReturn(referrerUrl).when(navigationEntry).getReferrerUrl(); + return tab; + } + + /** + * Test finding related tabs + */ + @Test + public void testRelatedTabsExist() throws Exception { + doReturn(sTab0).when(mTabModelFilter).getTabAt(eq(TAB_0_ID)); + doReturn(1).when(mTabModelFilter).getCount(); + doReturn(Arrays.asList(sTab0, sRelatedTab0, sRelatedTab1)) + .when(mTabModelFilter) + .getRelatedTabList(eq(TAB_0_ID)); + TabContext tabContext = TabContext.createCurrentContext(mTabModelSelector); + Assert.assertEquals(tabContext.getUngroupedTabs().size(), 0); + List<TabContext.TabGroupInfo> tabGroupInfo = tabContext.getTabGroups(); + Assert.assertEquals(1, tabGroupInfo.size()); + List<TabContext.TabInfo> groupedTabs = tabGroupInfo.get(0).tabs; + Assert.assertEquals(3, groupedTabs.size()); + Assert.assertEquals(TAB_0_ID, groupedTabs.get(0).id); + Assert.assertEquals(RELATED_TAB_0_ID, groupedTabs.get(1).id); + Assert.assertEquals(RELATED_TAB_1_ID, groupedTabs.get(2).id); + } + + /** + * Test finding no related tabs + */ + @Test + public void testFindNoRelatedTabs() throws Exception { + doReturn(sTab0).when(mTabModelFilter).getTabAt(eq(TAB_0_ID)); + doReturn(1).when(mTabModelFilter).getCount(); + doReturn(Arrays.asList(sTab0)).when(mTabModelFilter).getRelatedTabList(eq(TAB_0_ID)); + TabContext tabContext = TabContext.createCurrentContext(mTabModelSelector); + Assert.assertEquals(tabContext.getUngroupedTabs().size(), 1); + List<TabContext.TabGroupInfo> tabGroups = tabContext.getTabGroups(); + Assert.assertEquals(0, tabGroups.size()); + List<TabContext.TabInfo> ungroupedTabs = tabContext.getUngroupedTabs(); + Assert.assertEquals(1, ungroupedTabs.size()); + Assert.assertEquals(TAB_0_ID, ungroupedTabs.get(0).id); + } +}
diff --git a/chrome/android/features/tab_ui/tab_management_java_sources.gni b/chrome/android/features/tab_ui/tab_management_java_sources.gni index 2cd74b7..39da8ec 100644 --- a/chrome/android/features/tab_ui/tab_management_java_sources.gni +++ b/chrome/android/features/tab_ui/tab_management_java_sources.gni
@@ -14,6 +14,8 @@ "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleProvider.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java", + "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java", + "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestion.java", ] public_tab_management_java_sources += start_surface_public_java_sources @@ -33,4 +35,6 @@ "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallbackUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java", + "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java", + "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java", ]
diff --git a/chrome/android/java/res/layout/contact_view.xml b/chrome/android/java/res/layout/contact_view.xml index b8bad92..724b9c14 100644 --- a/chrome/android/java/res/layout/contact_view.xml +++ b/chrome/android/java/res/layout/contact_view.xml
@@ -16,7 +16,7 @@ android:id="@+id/content" style="@style/ListItemContainer"> - <include layout="@layout/modern_list_item_view" /> + <include layout="@layout/contacts_list_item_view" /> </LinearLayout> </org.chromium.chrome.browser.contacts_picker.ContactView>
diff --git a/chrome/android/java/res/layout/contacts_list_item_view.xml b/chrome/android/java/res/layout/contacts_list_item_view.xml new file mode 100644 index 0000000..00c8976 --- /dev/null +++ b/chrome/android/java/res/layout/contacts_list_item_view.xml
@@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2019 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. --> + +<merge + xmlns:android="http://schemas.android.com/apk/res/android"> + + <org.chromium.ui.widget.ChromeImageView + android:id="@+id/icon_view" + style="@style/ListItemStartIcon" /> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical" + android:layout_gravity="center_vertical" > + + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:maxLines="1" + android:ellipsize="end" + android:textAppearance="@style/TextAppearance.BlackTitle1" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + + <TextView + android:id="@+id/email" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxLines="1" + android:ellipsize="end" + android:textAppearance="@style/TextAppearance.BlackBody" /> + + <TextView + android:id="@+id/email_overflow_count" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="true" + android:maxLines="1" + android:paddingStart="4dp" + android:ellipsize="end" + android:textAppearance="@style/TextAppearance.ContactsPickerMoreDetails" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + + <TextView + android:id="@+id/telephone_number" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxLines="1" + android:ellipsize="end" + android:textAppearance="@style/TextAppearance.BlackBody" /> + + <TextView + android:id="@+id/telephone_number_overflow_count" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="true" + android:maxLines="1" + android:paddingStart="4dp" + android:ellipsize="end" + android:textAppearance="@style/TextAppearance.ContactsPickerMoreDetails" /> + </LinearLayout> + </LinearLayout> + +</merge>
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml index b479863..ff630e4 100644 --- a/chrome/android/java/res/values-v17/styles.xml +++ b/chrome/android/java/res/values-v17/styles.xml
@@ -776,6 +776,9 @@ <item name="android:textColor">@color/default_text_color</item> <item name="android:textSize">@dimen/text_size_large</item> </style> + <style name="TextAppearance.ContactsPickerMoreDetails" parent="TextAppearance.BlackBody"> + <item name="android:textColor">@color/default_text_color_link</item> + </style> <style name="TextAppearance.PageInfoPermissionSubtitle" parent="TextAppearance.BlackBody"> <item name="android:textColor">@color/secondary_text_default_material_light</item> </style>
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 302e0c36..6b52477 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -191,6 +191,7 @@ public static final String CCT_REPORT_PARALLEL_REQUEST_STATUS = "CCTReportParallelRequestStatus"; public static final String CCT_TARGET_TRANSLATE_LANGUAGE = "CCTTargetTranslateLanguage"; + public static final String CLOSE_TAB_SUGGESTIONS_STALE = "CloseTabSuggestionsStale"; public static final String CHROME_DUET = "ChromeDuet"; public static final String CHROME_DUET_ADAPTIVE = "ChromeDuetAdaptive"; public static final String DONT_AUTO_HIDE_BROWSER_CONTROLS = "DontAutoHideBrowserControls";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java index 04998a0..d8a2762 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
@@ -17,6 +17,18 @@ * A class to keep track of the metadata associated with a contact. */ public class ContactDetails implements Comparable<ContactDetails> { + /** + * A container class for delivering contact details in abbreviated form + * (where only the first email and phone numbers are returned and the rest + * is indicated with "+n more" strings). + */ + public static class AbbreviatedContactDetails { + public String primaryEmail; + public String overflowEmailCount; + public String primaryTelephoneNumber; + public String overflowTelephoneNumberCount; + } + // The unique id for the contact. private final String mId; @@ -87,16 +99,11 @@ /** * Accessor for the list of contact details (emails and phone numbers). Returned as strings * separated by newline). - * @param longVersion Whether to get all the details (for emails and phone numbers) or only what - * will fit in the allotted space on the dialog. * @param includeEmails Whether to include emails in the returned results. * @param includeTels Whether to include telephones in the returned results. - * @param resources The resources to use for fetching the string. Must be provided if - * longVersion is false, otherwise it can be null. * @return A string containing all the contact details registered for this contact. */ - public String getContactDetailsAsString(boolean longVersion, boolean includeEmails, - boolean includeTels, @Nullable Resources resources) { + public String getContactDetailsAsString(boolean includeEmails, boolean includeTels) { int count = 0; StringBuilder builder = new StringBuilder(); if (includeEmails) { @@ -105,12 +112,6 @@ builder.append("\n"); } builder.append(email); - if (!longVersion && mEmails.size() > 1) { - int size = mEmails.size() - 1; - builder.append(resources.getQuantityString( - R.plurals.contacts_picker_more_details, size, size)); - break; - } } } if (includeTels) { @@ -119,12 +120,6 @@ builder.append("\n"); } builder.append(phoneNumber); - if (!longVersion && mPhoneNumbers.size() > 1) { - int size = mPhoneNumbers.size() - 1; - builder.append(resources.getQuantityString( - R.plurals.contacts_picker_more_details, size, size)); - break; - } } } @@ -132,6 +127,42 @@ } /** + * Accessor for the list of contact details (emails and phone numbers). + * @param includeEmails Whether to include emails in the returned results. + * @param includeTels Whether to include telephones in the returned results. + * @param resources The resources to use for fetching the string. Must be provided. + * @return The contact details registered for this contact. + */ + public AbbreviatedContactDetails getAbbreviatedContactDetails( + boolean includeEmails, boolean includeTels, @Nullable Resources resources) { + AbbreviatedContactDetails results = new AbbreviatedContactDetails(); + + results.overflowEmailCount = ""; + if (!includeEmails || mEmails.size() == 0) { + results.primaryEmail = ""; + } else { + results.primaryEmail = mEmails.get(0); + if (mEmails.size() > 1) { + results.overflowEmailCount = resources.getQuantityString( + R.plurals.contacts_picker_more_details, (mEmails.size() - 1)); + } + } + + results.overflowTelephoneNumberCount = ""; + if (!includeTels || mPhoneNumbers.size() == 0) { + results.primaryTelephoneNumber = ""; + } else { + results.primaryTelephoneNumber = mPhoneNumbers.get(0); + if (mPhoneNumbers.size() > 1) { + results.overflowTelephoneNumberCount = resources.getQuantityString( + R.plurals.contacts_picker_more_details, (mPhoneNumbers.size() - 1)); + } + } + + return results; + } + + /** * A comparison function (results in a full name ascending sorting). * @param other The other ContactDetails object to compare it with. * @return 0, 1, or -1, depending on which is bigger.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java index bf07c6c..9a95eafb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
@@ -10,6 +10,7 @@ import android.graphics.drawable.BitmapDrawable; import android.support.v4.graphics.drawable.RoundedBitmapDrawable; import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; +import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import android.widget.TextView; @@ -40,10 +41,13 @@ private ContactDetails mContactDetails; // The display name of the contact. - public TextView mDisplayName; + private TextView mDisplayName; // The contact details for the contact. - public TextView mDetailsView; + private TextView mEmail; + private TextView mEmailOverflowCount; + private TextView mPhoneNumber; + private TextView mPhoneNumberOverflowCount; // The dialog manager to use to show contact details. private ModalDialogManager mManager; @@ -66,8 +70,23 @@ super.onFinishInflate(); mDisplayName = findViewById(R.id.title); - mDetailsView = findViewById(R.id.description); - mDetailsView.setMaxLines(2); + mEmail = findViewById(R.id.email); + mEmailOverflowCount = findViewById(R.id.email_overflow_count); + mPhoneNumber = findViewById(R.id.telephone_number); + mPhoneNumberOverflowCount = findViewById(R.id.telephone_number_overflow_count); + + mEmailOverflowCount.setOnClickListener(this); + mPhoneNumberOverflowCount.setOnClickListener(this); + } + + @Override + public void onClick(View view) { + int id = view.getId(); + if (id == R.id.email_overflow_count || id == R.id.telephone_number_overflow_count) { + onLongClick(this); + } else { + super.onClick(view); + } } @Override @@ -94,9 +113,9 @@ .with(ModalDialogProperties.CONTROLLER, controller) .with(ModalDialogProperties.TITLE, mContactDetails.getDisplayName()) .with(ModalDialogProperties.MESSAGE, - mContactDetails.getContactDetailsAsString(true, + mContactDetails.getContactDetailsAsString( PickerAdapter.includesEmails(), - PickerAdapter.includesTelephones(), null)) + PickerAdapter.includesTelephones())) .with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, mContext.getResources(), R.string.close) .build(); @@ -130,6 +149,11 @@ setSelectionDelegate(mSelectionDelegate); } + private void updateTextViewVisibilityAndContent(TextView view, String text) { + view.setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE); + view.setText(text); + } + /** * Completes the initialization of the ContactView. Must be called before the * {@link ContactView} can respond to click events. @@ -145,11 +169,17 @@ String displayName = contactDetails.getDisplayName(); mDisplayName.setText(displayName); - String details = contactDetails.getContactDetailsAsString( - /*longVersion=*/false, /*includeEmails=*/PickerAdapter.includesEmails(), - /*includeTels=*/PickerAdapter.includesTelephones(), mContext.getResources()); - mDetailsView.setText(details); - mDetailsView.setVisibility(details.isEmpty() ? View.GONE : View.VISIBLE); + ContactDetails.AbbreviatedContactDetails details = + contactDetails.getAbbreviatedContactDetails( + /*includeEmails=*/PickerAdapter.includesEmails(), + /*includeTels=*/PickerAdapter.includesTelephones(), + mContext.getResources()); + + updateTextViewVisibilityAndContent(mEmail, details.primaryEmail); + updateTextViewVisibilityAndContent(mEmailOverflowCount, details.overflowEmailCount); + updateTextViewVisibilityAndContent(mPhoneNumber, details.primaryTelephoneNumber); + updateTextViewVisibilityAndContent( + mPhoneNumberOverflowCount, details.overflowTelephoneNumberCount); if (icon == null) { icon = mCategoryView.getIconGenerator().generateIconForText( @@ -178,6 +208,9 @@ private void resetTile() { setIconDrawable(null); mDisplayName.setText(""); - mDetailsView.setText(""); + mEmail.setText(""); + mEmailOverflowCount.setText(""); + mPhoneNumber.setText(""); + mPhoneNumberOverflowCount.setText(""); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java index 263e4dc..5d79682 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
@@ -155,9 +155,7 @@ String query_lower = query.toLowerCase(Locale.getDefault()); for (ContactDetails contact : mContactDetails) { if (contact.getDisplayName().toLowerCase(Locale.getDefault()).contains(query_lower) - || contact.getContactDetailsAsString( - /*longVersion=*/true, includesEmails(), - includesTelephones(), /*resources=*/null) + || contact.getContactDetailsAsString(includesEmails(), includesTelephones()) .toLowerCase(Locale.getDefault()) .contains(query_lower)) { mSearchResults.add(count);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java index b505c73..9fa39d50 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.signin; +import android.app.Activity; import android.os.Bundle; import android.support.annotation.IntDef; import android.support.annotation.Nullable; @@ -145,7 +146,10 @@ } recordSigninCompletedHistogramAccountInfo(); - getActivity().finish(); + + Activity activity = getActivity(); + if (activity != null) activity.finish(); + callback.run(); }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 06b54bb..bdaba8a6d 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3539,10 +3539,10 @@ <message name="IDS_TOP_VIEW_TELEPHONE_FILTER_LABEL" desc="The label shown for the telephone filter toggle button (allowing the user to exclude emails)."> Phone numbers </message> - <message name="IDS_CONTACTS_PICKER_MORE_DETAILS" desc="Label describing that the user has one or more telephone/emails (used for either). The leading space is a word separator, for those languages that use space as a separator."> + <message name="IDS_CONTACTS_PICKER_MORE_DETAILS" desc="Label describing that the user has one or more telephone/emails (used for either)."> {DETAIL_COUNT, plural, - =1 { (+ 1 more)} - other { (+ # more)}} + =1 {(+ 1 more)} + other {(+ # more)}} </message> <message name="IDS_DISCLAIMER_SHARING_CONTACT_DETAILS" desc="Label describing what will happen with the contact details that are being shared."> The contacts you select will be shared with <ph name="BEGIN_BOLD"><b></ph><ph name="SITE">%1$s<ex>https://www.google.com</ex></ph><ph name="END_BOLD"></b></ph>.
diff --git a/chrome/app/file_pre_reader_win.h b/chrome/app/file_pre_reader_win.h deleted file mode 100644 index dcd596c..0000000 --- a/chrome/app/file_pre_reader_win.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file defines a function to pre-read a file in order to avoid touching -// the disk when it is subsequently used. - -#ifndef CHROME_APP_FILE_PRE_READER_WIN_H_ -#define CHROME_APP_FILE_PRE_READER_WIN_H_ - -namespace base { -class FilePath; -} - -// Pre-reads |file_path| to avoid touching the disk when the file is actually -// used. -void PreReadFile(const base::FilePath& file_path); - -#endif // CHROME_APP_FILE_PRE_READER_WIN_H_
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index ecf95aa..90ec9ba 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -5972,9 +5972,6 @@ <message name="IDS_PICTURE_IN_PICTURE_PLAY_PAUSE_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button toggles between play and pause controls."> Toggle video to play or pause </message> - <message name="IDS_PICTURE_IN_PICTURE_MUTE_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button toggles mute state."> - Toggle mute - </message> <message name="IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes next track action."> Next track </message>
diff --git a/chrome/app/main_dll_loader_win.cc b/chrome/app/main_dll_loader_win.cc index b5f9eb4b..a6d4064 100644 --- a/chrome/app/main_dll_loader_win.cc +++ b/chrome/app/main_dll_loader_win.cc
@@ -27,12 +27,12 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/trace_event.h" +#include "base/win/file_pre_reader.h" #include "base/win/scoped_handle.h" #include "base/win/shlwapi.h" #include "base/win/windows_version.h" #include "chrome/app/chrome_watcher_client_win.h" #include "chrome/app/chrome_watcher_command_line_win.h" -#include "chrome/app/file_pre_reader_win.h" #include "chrome/browser/active_use_util.h" #include "chrome/chrome_watcher/chrome_watcher_main_api.h" #include "chrome/common/chrome_constants.h" @@ -57,7 +57,7 @@ // reference to the loaded module on success, or null on error. HMODULE LoadModuleWithDirectory(const base::FilePath& module) { ::SetCurrentDirectoryW(module.DirName().value().c_str()); - PreReadFile(module); + base::win::PreReadFile(module, true); return ::LoadLibraryExW(module.value().c_str(), nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); }
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index be474a74..c215e76a 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -3870,9 +3870,6 @@ <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NEW_FINGERPRINT_DEFAULT_NAME" desc="The default name (plus a number for a newly added fingerprint)."> Finger <ph name="NEW_FINGER_NUMBER">$1<ex>1</ex></ph> </message> - <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_MEDIA_CONTROLS" desc="Label for the checkbox which enables or disables media controls on the lock screen."> - Enable Chrome media playback at lock screen - </message> <message name="IDS_SETTINGS_ACCOUNT_MANAGER_ADD_ACCOUNT_LABEL" desc="Label of the Add account button in Account Manager."> Add account </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index f57cef5..e30168b 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -489,6 +489,7 @@ "engagement/site_engagement_service.h", "engagement/site_engagement_service_factory.cc", "engagement/site_engagement_service_factory.h", + "expired_flags_list.h", "external_protocol/external_protocol_handler.cc", "external_protocol/external_protocol_handler.h", "external_protocol/external_protocol_observer.cc", @@ -1813,6 +1814,8 @@ "translate/translate_service.h", "undo/bookmark_undo_service_factory.cc", "undo/bookmark_undo_service_factory.h", + "unexpire_flags.cc", + "unexpire_flags.h", "unified_consent/unified_consent_service_factory.cc", "unified_consent/unified_consent_service_factory.h", "update_client/chrome_update_query_params_delegate.cc", @@ -1919,6 +1922,7 @@ deps = [ ":active_use_util", ":availability_protos", + ":expired_flags_list", ":ntp_background_proto", ":resource_prefetch_predictor_proto", "//base:i18n", @@ -3755,7 +3759,6 @@ ] deps += [ ":chrome_process_finder", - "//chrome:file_pre_reader", "//chrome/browser/safe_browsing/chrome_cleaner", "//chrome/browser/safe_browsing/chrome_cleaner:public", "//chrome/browser/win/conflicts:module_info", @@ -5373,6 +5376,27 @@ } } +action("expired_flags_list_gen") { + script = "//tools/flags/generate_expired_list.py" + sources = [ + "flag-metadata.json", + ] + outputs = [ + "$root_gen_dir/chrome/browser/expired_flags_list.cc", + ] + args = rebase_path(sources, root_build_dir) + + rebase_path(outputs, root_build_dir) +} + +source_set("expired_flags_list") { + deps = [ + ":expired_flags_list_gen", + ] + sources = [ + "$root_gen_dir/chrome/browser/expired_flags_list.cc", + ] +} + # Use a static library here because many test binaries depend on this but don't # require many files from it. This makes linking more efficient. static_library("test_support") {
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index d9bfea6d..b9f6c71d1 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -43,6 +43,7 @@ #include "chrome/browser/signin/account_consistency_mode_manager.h" #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h" #include "chrome/browser/ui/ui_features.h" +#include "chrome/browser/unexpire_flags.h" #include "chrome/common/buildflags.h" #include "chrome/common/channel_info.h" #include "chrome/common/chrome_content_client.h" @@ -467,6 +468,23 @@ kForceDark_SelectiveGeneralInversion, base::size(kForceDark_SelectiveGeneralInversion), nullptr}}; +#if defined(OS_ANDROID) +const FeatureEntry::FeatureParam kCloseTabSuggestionsStale_4Hours[] = { + {"close_tab_suggestions_stale_time_ms", "14400000"}}; +const FeatureEntry::FeatureParam kCloseTabSuggestionsStale_8Hours[] = { + {"close_tab_suggestions_stale_time_ms", "28800000"}}; +const FeatureEntry::FeatureParam kCloseTabSuggestionsStale_7Days[] = { + {"close_tab_suggestions_stale_time_ms", "604800000"}}; +const FeatureEntry::FeatureVariation kCloseTabSuggestionsStaleVariations[] = { + {"4 hours", kCloseTabSuggestionsStale_4Hours, + base::size(kCloseTabSuggestionsStale_4Hours), nullptr}, + {"8 hours", kCloseTabSuggestionsStale_8Hours, + base::size(kCloseTabSuggestionsStale_8Hours), nullptr}, + {"7 days", kCloseTabSuggestionsStale_7Days, + base::size(kCloseTabSuggestionsStale_7Days), nullptr}, +}; +#endif // OS_ANDROID + const FeatureEntry::Choice kEnableGpuRasterizationChoices[] = { {flags_ui::kGenericExperimentChoiceDefault, "", ""}, {flags_ui::kGenericExperimentChoiceEnabled, @@ -3213,6 +3231,13 @@ kStartSurfaceAndroidVariations, "StartSurfaceAndroid")}, + {"enable-close-tab-suggestions-stale", + flag_descriptions::kCloseTabSuggestionsStaleName, + flag_descriptions::kCloseTabSuggestionsStaleDescription, kOsAndroid, + FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kCloseTabSuggestionsStale, + kCloseTabSuggestionsStaleVariations, + "CloseSuggestionsStaleTab")}, + {"enable-horizontal-tab-switcher", flag_descriptions::kHorizontalTabSwitcherAndroidName, flag_descriptions::kHorizontalTabSwitcherAndroidDescription, kOsAndroid, @@ -4333,9 +4358,9 @@ // This set of flags is used to temporary reinstate expired flags; see // //docs/flag_expiry.md for details. - {"temporary-unexpire-flags-m78", flag_descriptions::kUnexpireFlagsM78Name, - flag_descriptions::kUnexpireFlagsM78Description, kOsAll, - FEATURE_VALUE_TYPE(flags_ui::kUnexpireFlagsM78)}, + {"temporary-unexpire-flags-m76", flag_descriptions::kUnexpireFlagsM76Name, + flag_descriptions::kUnexpireFlagsM76Description, kOsAll, + FEATURE_VALUE_TYPE(flags::kUnexpireFlagsM76)}, #if defined(OS_CHROMEOS) {"lock-screen-media-controls", @@ -4483,6 +4508,9 @@ return true; } + if (flags::IsFlagExpired(entry.internal_name)) + return true; + return false; }
diff --git a/chrome/browser/about_flags_browsertest.cc b/chrome/browser/about_flags_browsertest.cc index f7b80538..cc00a28 100644 --- a/chrome/browser/about_flags_browsertest.cc +++ b/chrome/browser/about_flags_browsertest.cc
@@ -5,13 +5,14 @@ #include "base/command_line.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/unexpire_flags.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" -#include "components/flags_ui/flags_state.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "ui/base/window_open_disposition.h" @@ -105,7 +106,7 @@ public testing::WithParamInterface<bool> { public: AboutFlagsBrowserTest() { - feature_list_.InitWithFeatures({flags_ui::kUnexpireFlagsM78}, {}); + feature_list_.InitWithFeatures({flags::kUnexpireFlagsM76}, {}); } void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index f05b6ec..b636d6ad 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -92,6 +92,7 @@ &kAndroidSiteSettingsUIRefresh, &kBackgroundTaskSchedulerForBackgroundSync, &kCastDeviceFilter, + &kCloseTabSuggestionsStale, &kCCTBackgroundTab, &kCCTExternalLinkHandling, &kCCTModule, @@ -282,6 +283,9 @@ const base::Feature kCastDeviceFilter{"CastDeviceFilter", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kCloseTabSuggestionsStale{ + "CloseTabSuggestionsStale", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kCCTBackgroundTab{"CCTBackgroundTab", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h index a295cb5..17d5d62 100644 --- a/chrome/browser/android/chrome_feature_list.h +++ b/chrome/browser/android/chrome_feature_list.h
@@ -25,6 +25,7 @@ extern const base::Feature kAndroidSiteSettingsUIRefresh; extern const base::Feature kBackgroundTaskComponentUpdate; extern const base::Feature kBackgroundTaskSchedulerForBackgroundSync; +extern const base::Feature kCloseTabSuggestionsStale; extern const base::Feature kCastDeviceFilter; extern const base::Feature kCCTBackgroundTab; extern const base::Feature kCCTExternalLinkHandling;
diff --git a/chrome/browser/chromeos/account_manager/account_manager_migrator.cc b/chrome/browser/chromeos/account_manager/account_manager_migrator.cc index e15b27da..85545ab2 100644 --- a/chrome/browser/chromeos/account_manager/account_manager_migrator.cc +++ b/chrome/browser/chromeos/account_manager/account_manager_migrator.cc
@@ -472,6 +472,12 @@ if (!chromeos::IsAccountManagerAvailable(profile_)) return; + if (migration_runner_ && (migration_runner_->GetStatus() == + AccountMigrationRunner::Status::kRunning)) { + return; + } + migration_runner_ = std::make_unique<AccountMigrationRunner>(); + ran_migration_steps_ = false; if (ShouldRunMigrations()) { ran_migration_steps_ = true; @@ -481,7 +487,7 @@ // Cleanup tasks (like re-enabling Chrome account reconciliation) rely on the // migration being run, even if they were no-op. Check // |OnMigrationRunComplete| and |RunCleanupTasks|. - migration_runner_.Run( + migration_runner_->Run( base::BindOnce(&AccountManagerMigrator::OnMigrationRunComplete, weak_factory_.GetWeakPtr())); } @@ -524,7 +530,7 @@ signin::IdentityManager* identity_manager = IdentityManagerFactory::GetForProfile(profile_); - migration_runner_.AddStep(std::make_unique<DeviceAccountMigration>( + migration_runner_->AddStep(std::make_unique<DeviceAccountMigration>( GetDeviceAccount(profile_), ProfileHelper::Get() ->GetUserByProfile(profile_) @@ -538,14 +544,14 @@ chromeos::prefs::kSecondaryGoogleAccountSigninAllowed); if (is_secondary_google_account_signin_allowed) { - migration_runner_.AddStep(std::make_unique<ContentAreaAccountsMigration>( + migration_runner_->AddStep(std::make_unique<ContentAreaAccountsMigration>( account_manager, identity_manager)); if (arc::IsArcProvisioned(profile_)) { // Add a migration step for ARC only if ARC has been provisioned. If ARC // has not been provisioned yet, there cannot be any accounts that need to // be migrated. - migration_runner_.AddStep(std::make_unique<ArcAccountsMigration>( + migration_runner_->AddStep(std::make_unique<ArcAccountsMigration>( account_manager, identity_manager, arc::ArcAuthService::GetForBrowserContext( profile_) /* arc_auth_service */)); @@ -557,22 +563,32 @@ // This MUST be the last step. Check the class level documentation of // |SuccessStorage| for the reason. - migration_runner_.AddStep( + migration_runner_->AddStep( std::make_unique<SuccessStorage>(profile_->GetPrefs())); // TODO(sinhak): Verify Device Account LST state. } AccountMigrationRunner::Status AccountManagerMigrator::GetStatus() const { - return migration_runner_.GetStatus(); + if (!migration_runner_) + return AccountMigrationRunner::Status::kNotStarted; + + return migration_runner_->GetStatus(); +} + +base::Optional<AccountMigrationRunner::MigrationResult> +AccountManagerMigrator::GetLastMigrationRunResult() const { + return last_migration_run_result_; } void AccountManagerMigrator::OnMigrationRunComplete( const AccountMigrationRunner::MigrationResult& result) { DCHECK_NE(AccountMigrationRunner::Status::kNotStarted, - migration_runner_.GetStatus()); + migration_runner_->GetStatus()); DCHECK_NE(AccountMigrationRunner::Status::kRunning, - migration_runner_.GetStatus()); + migration_runner_->GetStatus()); + + last_migration_run_result_ = base::make_optional(result); VLOG(1) << "Account migrations completed with result: " << static_cast<int>(result.final_status);
diff --git a/chrome/browser/chromeos/account_manager/account_manager_migrator.h b/chrome/browser/chromeos/account_manager/account_manager_migrator.h index 9530dae..614bea9 100644 --- a/chrome/browser/chromeos/account_manager/account_manager_migrator.h +++ b/chrome/browser/chromeos/account_manager/account_manager_migrator.h
@@ -5,8 +5,11 @@ #ifndef CHROME_BROWSER_CHROMEOS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_MIGRATOR_H_ #define CHROME_BROWSER_CHROMEOS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_MIGRATOR_H_ +#include <memory> + #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "chrome/browser/chromeos/account_manager/account_migration_runner.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "components/keyed_service/core/keyed_service.h" @@ -31,6 +34,11 @@ // Gets the current status of migration. AccountMigrationRunner::Status GetStatus() const; + // Gets the result of the last migration run. If migrations have not been run + // before, the optional will be empty. + base::Optional<AccountMigrationRunner::MigrationResult> + GetLastMigrationRunResult() const; + private: // Returns whether migrations should be run or skipped. bool ShouldRunMigrations() const; @@ -49,12 +57,17 @@ Profile* const profile_; // Used for running migration steps. - chromeos::AccountMigrationRunner migration_runner_; + std::unique_ptr<AccountMigrationRunner> migration_runner_ = nullptr; // Stores if any migration steps were actually run. It is possible for the // migration flow to be a no-op, in which case this will be |false|. bool ran_migration_steps_ = false; + // Result of the last migration run. Empty if migrations have not been run + // before. + base::Optional<AccountMigrationRunner::MigrationResult> + last_migration_run_result_; + base::WeakPtrFactory<AccountManagerMigrator> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(AccountManagerMigrator); };
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc index 2028cce..322e4f2 100644 --- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc +++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
@@ -50,11 +50,6 @@ return false; } -bool ArcPictureInPictureWindowControllerImpl::IsPlayerMuted() { - // Should be a no-op on ARC. This is managed on the Android side. - return false; -} - content::WebContents* ArcPictureInPictureWindowControllerImpl::GetInitiatorWebContents() { // Should be a no-op on ARC. This is managed on the Android side. @@ -67,30 +62,16 @@ // Should be a no-op on ARC. This is managed on the Android side. } -void ArcPictureInPictureWindowControllerImpl::UpdateMutedState() { - // Should be a no-op on ARC. This is managed on the Android side. -} - bool ArcPictureInPictureWindowControllerImpl::TogglePlayPause() { // Should be a no-op on ARC. This is managed on the Android side. return false; } -bool ArcPictureInPictureWindowControllerImpl::ToggleMute() { - // Should be a no-op on ARC. This is managed on the Android side. - return false; -} - void ArcPictureInPictureWindowControllerImpl::SetAlwaysHidePlayPauseButton( bool is_visible) { // Should be a no-op on ARC. This is managed on the Android side. } -void ArcPictureInPictureWindowControllerImpl::SetAlwaysHideMuteButton( - bool is_visible) { - // Should be a no-op on ARC. This is managed on the Android side. -} - void ArcPictureInPictureWindowControllerImpl::SkipAd() { // Should be a no-op on ARC. This is managed on the Android side. }
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h index b3dc339..f71c45c 100644 --- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h +++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
@@ -37,15 +37,11 @@ content::OverlayWindow* GetWindowForTesting() override; void UpdateLayerBounds() override; bool IsPlayerActive() override; - bool IsPlayerMuted() override; content::WebContents* GetInitiatorWebContents() override; bool TogglePlayPause() override; - bool ToggleMute() override; void UpdatePlaybackState(bool is_playing, bool reached_end_of_stream) override; - void UpdateMutedState() override; void SetAlwaysHidePlayPauseButton(bool is_visible) override; - void SetAlwaysHideMuteButton(bool is_visible) override; void SkipAd() override; void NextTrack() override; void PreviousTrack() override;
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc index b8f2ad3..0f5fccf9 100644 --- a/chrome/browser/chromeos/crostini/crostini_manager.cc +++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -534,6 +534,30 @@ } } +void CrostiniManager::SetContainerOsRelease( + std::string vm_name, + std::string container_name, + const vm_tools::cicerone::OsRelease& os_release) { + container_os_releases_.emplace(ContainerId(vm_name, container_name), + os_release); + VLOG(1) << "vm_name: " << vm_name << " container_name: " << container_name; + VLOG(1) << "os_release.pretty_name " << os_release.pretty_name(); + VLOG(1) << "os_release.name " << os_release.name(); + VLOG(1) << "os_release.version " << os_release.version(); + VLOG(1) << "os_release.version_id " << os_release.version_id(); + VLOG(1) << "os_release.id " << os_release.id(); +} + +const vm_tools::cicerone::OsRelease* CrostiniManager::GetContainerOsRelease( + std::string vm_name, + std::string container_name) { + auto it = container_os_releases_.find(ContainerId(vm_name, container_name)); + if (it != container_os_releases_.end()) { + return &it->second; + } + return nullptr; +} + base::Optional<ContainerInfo> CrostiniManager::GetContainerInfo( std::string vm_name, std::string container_name) { @@ -2117,6 +2141,9 @@ NOTREACHED(); break; } + if (response->has_os_release()) { + SetContainerOsRelease(vm_name, container_name, response->os_release()); + } } void CrostiniManager::OnSetUpLxdContainerUser( @@ -2257,6 +2284,10 @@ VLOG(1) << "Awaiting ContainerStarted signal from Garcon"; return; } + if (signal.has_os_release()) { + SetContainerOsRelease(signal.vm_name(), signal.container_name(), + signal.os_release()); + } // Find the callbacks to call, then erase them from the map. auto range = start_container_callbacks_.equal_range( std::make_tuple(signal.vm_name(), signal.container_name()));
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h index d900f0f..c4dafd6e 100644 --- a/chrome/browser/chromeos/crostini/crostini_manager.h +++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -481,6 +481,12 @@ void SetContainerSshfsMounted(std::string vm_name, std::string container_name, bool is_mounted); + void SetContainerOsRelease(std::string vm_name, + std::string container_name, + const vm_tools::cicerone::OsRelease& os_release); + const vm_tools::cicerone::OsRelease* GetContainerOsRelease( + std::string vm_name, + std::string container_name); // Returns null if VM or container is not running. base::Optional<ContainerInfo> GetContainerInfo(std::string vm_name, std::string container_name); @@ -731,6 +737,10 @@ // Running containers as keyed by vm name. std::multimap<std::string, ContainerInfo> running_containers_; + // OsRelease protos keyed by ContainerId. We populate this map even if a + // container fails to start normally. + std::map<ContainerId, vm_tools::cicerone::OsRelease> container_os_releases_; + std::vector<RemoveCrostiniCallback> remove_crostini_callbacks_; base::ObserverList<LinuxPackageOperationProgressObserver>::Unchecked
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc index ee8f7e0..16e9aade 100644 --- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc +++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -3,7 +3,9 @@ // found in the LICENSE file. #include "chrome/browser/chromeos/crostini/crostini_manager.h" + #include <memory> + #include "base/base64.h" #include "base/bind.h" #include "base/memory/ptr_util.h" @@ -928,6 +930,28 @@ EXPECT_FALSE(crostini_manager()->GetContainerInfo(kVmName, kContainerName)); } +TEST_F(CrostiniManagerRestartTest, OsReleaseSetCorrectly) { + vm_tools::cicerone::OsRelease os_release; + os_release.set_pretty_name("Debian GNU/Linux 10 (buster)"); + fake_cicerone_client_->set_lxd_container_os_release(os_release); + + restart_id_ = crostini_manager()->RestartCrostini( + kVmName, kContainerName, + base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback, + base::Unretained(this), run_loop()->QuitClosure()), + this); + EXPECT_TRUE(crostini_manager()->IsRestartPending(restart_id_)); + run_loop()->Run(); + + const auto* stored_os_release = + crostini_manager()->GetContainerOsRelease(kVmName, kContainerName); + EXPECT_NE(stored_os_release, nullptr); + // Sadly, we can't use MessageDifferencer here because we're using the LITE + // API in our protos. + EXPECT_EQ(os_release.SerializeAsString(), + stored_os_release->SerializeAsString()); +} + TEST_F(CrostiniManagerRestartTest, RestartThenUninstall) { restart_id_ = crostini_manager()->RestartCrostini( kVmName, kContainerName,
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h index 469fb2c..ab94a63 100644 --- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h +++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h
@@ -135,7 +135,7 @@ wilco_dtc_supportd::mojom::WilcoDtcSupportdServicePtr wilco_dtc_supportd_service_mojo_ptr_; - // The service to perform diagnostics_processor's web requests. + // The service to perform wilco_dtc_supportd's web requests. WilcoDtcSupportdWebRequestService web_request_service_; // The wilco_dtc_supportd notification controller in charge of sending
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h index d3e3dbeb..ff186c4f7 100644 --- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h +++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h
@@ -29,13 +29,14 @@ extern const int kWilcoDtcSupportdUiMessageMaxSize; // Creates an extensions native message host that talks to the -// diagnostics_processor daemon. This should be used when the communication is -// initiated by the extension (i.e., not the daemon). +// wilco_dtc_supportd daemon. +// This should be used when the communication is initiated by the extension +// (i.e., not the daemon). std::unique_ptr<extensions::NativeMessageHost> CreateExtensionOwnedWilcoDtcSupportdMessageHost(); -// Delivers the UI message |json_message| from the diagnostics_processor daemon -// to the extensions that are allowed to receive it. The delivery is done via +// Delivers the UI message |json_message| from the wilco_dtc_supportd daemon to +// the extensions that are allowed to receive it. The delivery is done via // creating extensions native message hosts. |send_response_callback| will be // called with the response from the extension (the first non-empty one in case // of multiple extensions providing some responses).
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc index 576dc4d..a7063820 100644 --- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc +++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc
@@ -190,9 +190,9 @@ sender: "WilcoDtcSupportd" description: "Perform a web request." trigger: - "diagnostics_processor performs a web request to their server." + "wilco_dtc_supportd performs a web request to their server." data: - "diagnostics_processor's proprietary data." + "wilco_dtc_supportd's proprietary data." destination: OTHER } policy {
diff --git a/chrome/browser/expired_flags_list.h b/chrome/browser/expired_flags_list.h new file mode 100644 index 0000000..cc2ae77 --- /dev/null +++ b/chrome/browser/expired_flags_list.h
@@ -0,0 +1,24 @@ +// Copyright 2019 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_EXPIRED_FLAGS_LIST_H_ +#define CHROME_BROWSER_EXPIRED_FLAGS_LIST_H_ + +// This header file declares a data structure that is generated at compile time +// by //tools/flags/generate_expired_list.py - also see the +// //chrome/browser:expired_flags_list target. + +namespace flags { + +struct ExpiredFlag { + const char* name; + int mstone; +}; + +// This array of names is terminated with a flag whose name is nullptr. +extern const ExpiredFlag kExpiredFlags[]; + +} // namespace flags + +#endif // CHROME_BROWSER_EXPIRED_FLAGS_LIST_H_
diff --git a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc index 620e7fa6..9e1dae7 100644 --- a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc +++ b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
@@ -42,11 +42,14 @@ IsTimeZoneResolutionPolicyControlled()) { out_pref->controlled_by = settings_api::CONTROLLED_BY_DEVICE_POLICY; out_pref->enforcement = settings_api::ENFORCEMENT_ENFORCED; - } else if (profile_->IsChild() && - !base::FeatureList::IsEnabled( - features::kParentAccessCodeForTimeChange)) { - out_pref->controlled_by = settings_api::ControlledBy::CONTROLLED_BY_PARENT; - out_pref->enforcement = settings_api::ENFORCEMENT_ENFORCED; + } else if (profile_->IsChild()) { + out_pref->controlled_by = settings_api::CONTROLLED_BY_PARENT; + if (base::FeatureList::IsEnabled( + features::kParentAccessCodeForTimeChange)) { + out_pref->enforcement = settings_api::ENFORCEMENT_PARENT_SUPERVISED; + } else { + out_pref->enforcement = settings_api::ENFORCEMENT_ENFORCED; + } } else if (!profile_->IsSameProfile( ProfileManager::GetPrimaryUserProfile())) { out_pref->controlled_by = settings_api::CONTROLLED_BY_PRIMARY_USER;
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 9e59c6e..4882c773 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -477,8 +477,6 @@ settings_api::PrefType::PREF_TYPE_BOOLEAN; (*s_whitelist)[prefs::kRestoreLastLockScreenNote] = settings_api::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)[ash::prefs::kLockScreenMediaControlsEnabled] = - settings_api::PrefType::PREF_TYPE_BOOLEAN; (*s_whitelist)[::prefs::kSettingsShowBrowserBanner] = settings_api::PrefType::PREF_TYPE_BOOLEAN;
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc index b544f0d..dcbc0a9 100644 --- a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc +++ b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
@@ -42,6 +42,7 @@ #include "ui/gl/gl_switches.h" #if BUILDFLAG(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/supervised_user/logged_in_user_mixin.h" #include "chrome/browser/supervised_user/supervised_user_constants.h" #if defined(OS_CHROMEOS) @@ -375,23 +376,97 @@ class ExtensionWebstorePrivateApiTestChild : public ExtensionWebstorePrivateApiTest { public: - void SetUpCommandLine(base::CommandLine* command_line) override { - ExtensionWebstorePrivateApiTest::SetUpCommandLine(command_line); - command_line->AppendSwitchASCII(switches::kSupervisedUserId, - supervised_users::kChildAccountSUID); -#if defined(OS_CHROMEOS) - command_line->AppendSwitchASCII( - chromeos::switches::kLoginUser, - "supervised_user@locally-managed.localhost"); - command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "hash"); -#endif + ExtensionWebstorePrivateApiTestChild() + : embedded_test_server_(std::make_unique<net::EmbeddedTestServer>()), + logged_in_user_mixin_(&mixin_host_, + chromeos::LoggedInUserMixin::LogInType::kChild, + embedded_test_server_.get()) { + // Suppress regular user login to enable child user login. + set_chromeos_user_ = false; + // Launch a browser instance after logging in. + logged_in_user_mixin_.set_should_launch_browser(true); } + + void SetUp() override { + mixin_host_.SetUp(); + ExtensionWebstorePrivateApiTest::SetUp(); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + mixin_host_.SetUpCommandLine(command_line); + ExtensionWebstorePrivateApiTest::SetUpCommandLine(command_line); + // Shortens the merge session timeout from 20 to 1 seconds to speed up the + // test by about 19 seconds. + // TODO (crbug.com/995575): figure out why this switch speeds up the test, + // and fix the test setup so this is not required. + command_line->AppendSwitch(switches::kShortMergeSessionTimeoutForTest); + } + + void SetUpDefaultCommandLine(base::CommandLine* command_line) override { + mixin_host_.SetUpDefaultCommandLine(command_line); + ExtensionWebstorePrivateApiTest::SetUpDefaultCommandLine(command_line); + } + + bool SetUpUserDataDirectory() override { + return mixin_host_.SetUpUserDataDirectory() && + ExtensionWebstorePrivateApiTest::SetUpUserDataDirectory(); + } + + void SetUpInProcessBrowserTestFixture() override { + mixin_host_.SetUpInProcessBrowserTestFixture(); + ExtensionWebstorePrivateApiTest::SetUpInProcessBrowserTestFixture(); + } + + void CreatedBrowserMainParts( + content::BrowserMainParts* browser_main_parts) override { + mixin_host_.CreatedBrowserMainParts(browser_main_parts); + ExtensionWebstorePrivateApiTest::CreatedBrowserMainParts( + browser_main_parts); + } + + void SetUpOnMainThread() override { + mixin_host_.SetUpOnMainThread(); + ExtensionWebstorePrivateApiTest::SetUpOnMainThread(); + // Needed for resolving FakeGaiaMixin token requests. + // Otherwise the test times out. + host_resolver()->AddRule("*", "127.0.0.1"); + logged_in_user_mixin_.LogInUser(true /* issue_any_scope_token */); + // Set the private |browser_| member in InProcessBrowserTest. + // Otherwise calls to InProcessBrowserTest::browser() returns null and leads + // to segmentation faults. + SelectFirstBrowser(); + } + + void TearDownOnMainThread() override { + mixin_host_.TearDownOnMainThread(); + ExtensionWebstorePrivateApiTest::TearDownOnMainThread(); + } + + void TearDownInProcessBrowserTestFixture() override { + mixin_host_.TearDownInProcessBrowserTestFixture(); + ExtensionWebstorePrivateApiTest::TearDownInProcessBrowserTestFixture(); + } + + void TearDown() override { + mixin_host_.TearDown(); + ExtensionWebstorePrivateApiTest::TearDown(); + } + + private: + // Replicate what MixinBasedInProcessBrowserTest does since inheriting from + // that class is inconvenient here. + InProcessBrowserTestMixinHost mixin_host_; + // Create another embedded test server to avoid starting the same one twice. + std::unique_ptr<net::EmbeddedTestServer> embedded_test_server_; + + chromeos::LoggedInUserMixin logged_in_user_mixin_; }; // Tests that extension installation is blocked for child accounts, and // attempting to do so produces a special error code. // Note: This will have to be updated when we enable child-initiated installs. IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTestChild, InstallBlocked) { + ASSERT_TRUE(browser()); ASSERT_TRUE(RunInstallTest("begin_install_fail_child.html", "extension.crx")); }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 3aa3e4e..37d0215 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1018,6 +1018,11 @@ "expiry_milestone": 79 }, { + "name": "enable-close-tab-suggestions-stale", + "owners": [ "memex-team@google.com" ], + "expiry_milestone": 82 + }, + { "name": "enable-cloud-print-xps", "owners": [ "//printing/OWNERS" ], "expiry_milestone": 76 @@ -1279,7 +1284,7 @@ { "name": "enable-implicit-root-scroller", "owners": [ "bokan", "input-dev" ], - "expiry_milestone": 75 + "expiry_milestone": 80 }, { "name": "enable-incognito-window-counter", @@ -1736,7 +1741,7 @@ { "name": "enable-text-fragment-anchor", "owners": [ "bokan", "input-dev" ], - "expiry_milestone": 77 + "expiry_milestone": 80 }, { "name": "enable-tls13-early-data", @@ -3077,9 +3082,9 @@ "expiry_milestone": 81 }, { - "name": "temporary-unexpire-flags-m78", + "name": "temporary-unexpire-flags-m76", "owners": [ "ellyjones", "flags-dev" ], - "expiry_milestone": 81 + "expiry_milestone": 80 }, { "name": "terminal-system-app",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index f0009590..adae9fa1 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1982,9 +1982,9 @@ "Insecure origins treated as secure"; const char kTreatInsecureOriginAsSecureDescription[] = "Treat given (insecure) origins as secure origins. Multiple origins can be " - "supplied as a comma-separated list. For the definition of secure " - "contexts, " - "see https://w3c.github.io/webappsec-secure-contexts/"; + "supplied as a comma-separated list. Origins must have their protocol " + "specified e.g. \"http://example.com\". For the definition of secure " + "contexts, see https://w3c.github.io/webappsec-secure-contexts/"; const char kTreatUnsafeDownloadsAsActiveName[] = "Treat risky downloads over insecure connections as active mixed content"; @@ -2008,9 +2008,9 @@ "Reduces disk activity during media playback, which can result in " "power savings."; -const char kUnexpireFlagsM78Name[] = "Temporarily unexpire M78 flags."; -const char kUnexpireFlagsM78Description[] = - "Temporarily unexpire flags that are expired as of M78. These flags will " +const char kUnexpireFlagsM76Name[] = "Temporarily unexpire M76 flags."; +const char kUnexpireFlagsM76Description[] = + "Temporarily unexpire flags that are expired as of M76. These flags will " "be removed soon."; const char kUnifiedConsentName[] = "Unified Consent"; @@ -2284,6 +2284,10 @@ const char kClickToCallOpenDialerDirectlyDescription[] = "Enables opening the dialer directly instead of displaying a notification. " "Only available on Android P- and when the screen is on and unlocked."; +const char kCloseTabSuggestionsStaleName[] = "Suggest to close stale Tabs"; +const char kCloseTabSuggestionsStaleDescription[] = + "Suggests to the user to close Tabs that have not been used above a " + "threshold such as 1 day. The threshold is configurable."; const char kClickToCallReceiverName[] = "Enable receiver device to handle click to call feature";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 8304670..8f5262a 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1195,8 +1195,8 @@ extern const char kTurnOffStreamingMediaCachingName[]; extern const char kTurnOffStreamingMediaCachingDescription[]; -extern const char kUnexpireFlagsM78Name[]; -extern const char kUnexpireFlagsM78Description[]; +extern const char kUnexpireFlagsM76Name[]; +extern const char kUnexpireFlagsM76Description[]; extern const char kUnifiedConsentName[]; extern const char kUnifiedConsentDescription[]; @@ -1361,6 +1361,9 @@ extern const char kClickToCallOpenDialerDirectlyName[]; extern const char kClickToCallOpenDialerDirectlyDescription[]; +extern const char kCloseTabSuggestionsStaleName[]; +extern const char kCloseTabSuggestionsStaleDescription[]; + extern const char kClickToCallReceiverName[]; extern const char kClickToCallReceiverDescription[];
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc index c3f12f0..8d1be4a 100644 --- a/chrome/browser/media/encrypted_media_browsertest.cc +++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -829,7 +829,8 @@ kEmeSessionClosedAndError); } -IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, FileIOTest) { +// Flaky: crbug.com/997953 +IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, DISABLED_FileIOTest) { TestNonPlaybackCases(kExternalClearKeyFileIOTestKeySystem, kUnitTestSuccess); }
diff --git a/chrome/browser/picture_in_picture/DEPS b/chrome/browser/picture_in_picture/DEPS index 8e81e30..3196882 100644 --- a/chrome/browser/picture_in_picture/DEPS +++ b/chrome/browser/picture_in_picture/DEPS
@@ -1,6 +1,5 @@ specific_include_rules = { "picture_in_picture_window_controller_browsertest\.cc": [ - "+chrome/browser/ui/views/overlay/mute_image_button.h", "+chrome/browser/ui/views/overlay/overlay_window_views.h", "+chrome/browser/ui/views/overlay/playback_image_button.h", "+chrome/browser/ui/views/overlay/skip_ad_label_button.h",
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc index b520626..44776b9e 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -18,7 +18,6 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/views/overlay/mute_image_button.h" #include "chrome/browser/ui/views/overlay/overlay_window_views.h" #include "chrome/browser/ui/views/overlay/playback_image_button.h" #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h" @@ -76,14 +75,10 @@ MOCK_METHOD0(GetWindowForTesting, content::OverlayWindow*()); MOCK_METHOD0(UpdateLayerBounds, void()); MOCK_METHOD0(IsPlayerActive, bool()); - MOCK_METHOD0(IsPlayerMuted, bool()); MOCK_METHOD0(GetInitiatorWebContents, content::WebContents*()); MOCK_METHOD2(UpdatePlaybackState, void(bool, bool)); - MOCK_METHOD0(UpdateMutedState, void()); MOCK_METHOD0(TogglePlayPause, bool()); - MOCK_METHOD0(ToggleMute, bool()); MOCK_METHOD1(SetAlwaysHidePlayPauseButton, void(bool)); - MOCK_METHOD1(SetAlwaysHideMuteButton, void(bool)); MOCK_METHOD0(SkipAd, void()); MOCK_METHOD0(NextTrack, void()); MOCK_METHOD0(PreviousTrack, void()); @@ -1674,7 +1669,7 @@ EXPECT_FALSE(is_paused); } -// Tests that the back-to-tab, close, mute and resize controls move properly as +// Tests that the back-to-tab, close, and resize controls move properly as // the window changes quadrants. IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest, MovingQuadrantsMovesBackToTabAndResizeControls) { @@ -2934,198 +2929,6 @@ .WaitAndGetTitle()); } -class MuteButtonPictureInPictureWindowControllerBrowserTest - : public PictureInPictureWindowControllerBrowserTest { - public: - void SetUpCommandLine(base::CommandLine* command_line) override { - PictureInPictureWindowControllerBrowserTest::SetUpCommandLine(command_line); - command_line->AppendSwitchASCII("enable-blink-features", "MuteButton"); - } -}; - -// Tests the mute button and its state in the Picture-in-Picture window when -// experimental feature MuteButton is enabled. -IN_PROC_BROWSER_TEST_F(MuteButtonPictureInPictureWindowControllerBrowserTest, - MuteButtonEnabled) { - LoadTabAndEnterPictureInPicture( - browser(), base::FilePath(kPictureInPictureWindowSizePage)); - - OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>( - window_controller()->GetWindowForTesting()); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kUnmuted); - - content::WebContents* active_web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - - // Play video-only mediastream. - bool result = false; - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - active_web_contents, "changeVideoSrcToMediaStream();", &result)); - EXPECT_TRUE(result); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kNoAudio); - - // Play back video. - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - active_web_contents, "changeVideoSrc();", &result)); - EXPECT_TRUE(result); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kUnmuted); - - // Play no-audio track video. - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - active_web_contents, "changeVideoSrcToNoAudioTrackVideo();", &result)); - EXPECT_TRUE(result); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kNoAudio); - - // Play back video. - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - active_web_contents, "changeVideoSrc();", &result)); - EXPECT_TRUE(result); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kUnmuted); - - // Mute second video and enter Picture-in-Picture for second video. - EXPECT_TRUE( - content::ExecuteScript(active_web_contents, "secondVideo.muted = true;")); - ASSERT_TRUE( - content::ExecuteScript(active_web_contents, "secondPictureInPicture();")); - base::string16 expected_title = base::ASCIIToUTF16("leavepictureinpicture"); - EXPECT_EQ(expected_title, - content::TitleWatcher(active_web_contents, expected_title) - .WaitAndGetTitle()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kMuted); - - // Re-enter Picture-in-Picture for first video. - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - active_web_contents, "enterPictureInPicture();", &result)); - EXPECT_TRUE(result); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kUnmuted); - - // Mute video from website. - EXPECT_TRUE( - content::ExecuteScript(active_web_contents, "video.muted = true;")); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kMuted); - - // Unmute video from website. - EXPECT_TRUE( - content::ExecuteScript(active_web_contents, "video.muted = false;")); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kUnmuted); - - ASSERT_TRUE(content::ExecuteScript(active_web_contents, - "addVolumeChangeEventListener();")); - - // Simulates user clicking mute button. - window_controller()->ToggleMute(); - expected_title = base::ASCIIToUTF16("muted: true"); - EXPECT_EQ(expected_title, - content::TitleWatcher(active_web_contents, expected_title) - .WaitAndGetTitle()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kMuted); - - // Simulates user clicking unmute button. - window_controller()->ToggleMute(); - expected_title = base::ASCIIToUTF16("muted: false"); - EXPECT_EQ(expected_title, - content::TitleWatcher(active_web_contents, expected_title) - .WaitAndGetTitle()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kUnmuted); - - // Umute second video and enter Picture-in-Picture for second video. - EXPECT_TRUE(content::ExecuteScript(active_web_contents, - "secondVideo.muted = false;")); - ASSERT_TRUE( - content::ExecuteScript(active_web_contents, "secondPictureInPicture();")); - expected_title = base::ASCIIToUTF16("leavepictureinpicture"); - EXPECT_EQ(expected_title, - content::TitleWatcher(active_web_contents, expected_title) - .WaitAndGetTitle()); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kUnmuted); -} - -// Tests the mute button and its state in the Picture-in-Picture window when -// experimental feature MuteButton is disabled. -IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest, - MuteButtonDisabled) { - LoadTabAndEnterPictureInPicture( - browser(), base::FilePath(kPictureInPictureWindowSizePage)); - - OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>( - window_controller()->GetWindowForTesting()); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kNoAudio); - - content::WebContents* active_web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - - // Play video-only mediastream. - bool result = false; - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - active_web_contents, "changeVideoSrcToMediaStream();", &result)); - EXPECT_TRUE(result); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kNoAudio); - - // Play back video. - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - active_web_contents, "changeVideoSrc();", &result)); - EXPECT_TRUE(result); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kNoAudio); - - // Play no-audio track video. - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - active_web_contents, "changeVideoSrcToNoAudioTrackVideo();", &result)); - EXPECT_TRUE(result); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kNoAudio); - - // Play back video. - ASSERT_TRUE(content::ExecuteScriptAndExtractBool( - active_web_contents, "changeVideoSrc();", &result)); - EXPECT_TRUE(result); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kNoAudio); - - // Mute video from website. - EXPECT_TRUE( - content::ExecuteScript(active_web_contents, "video.muted = true;")); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kNoAudio); - - // Unmute video from website. - EXPECT_TRUE( - content::ExecuteScript(active_web_contents, "video.muted = false;")); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(overlay_window->muted_state_for_testing(), - OverlayWindowViews::MutedState::kNoAudio); -} - // Tests that when closing the window after the player was reset, the <video> // element is still notified. IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
diff --git a/chrome/browser/predictors/predictor_database.cc b/chrome/browser/predictors/predictor_database.cc index 8e9072b..7c3b48d 100644 --- a/chrome/browser/predictors/predictor_database.cc +++ b/chrome/browser/predictors/predictor_database.cc
@@ -103,6 +103,7 @@ } bool success = db_->Open(db_path_); + db_->Preload(); if (!success) return;
diff --git a/chrome/browser/previews/defer_all_script_browsertest.cc b/chrome/browser/previews/defer_all_script_browsertest.cc index 70f7c53..fe49f68a 100644 --- a/chrome/browser/previews/defer_all_script_browsertest.cc +++ b/chrome/browser/previews/defer_all_script_browsertest.cc
@@ -312,8 +312,6 @@ true); } -// Disable flake on Linux too (via only Android) until crbug/997697 resolved. -#if defined(OS_ANDROID) IN_PROC_BROWSER_TEST_F( DeferAllScriptBrowserTest, DISABLE_ON_WIN_MAC_CHROMESOS(DeferAllScriptClientRedirectLoopStopped)) { @@ -333,8 +331,8 @@ ui_test_utils::NavigateToURL(browser(), client_redirect_url()); RetryForHistogramUntilCountReached( - &histogram_tester, "PageLoad.DocumentTiming.NavigationToLoadEventFired", - 1); + &histogram_tester, "Navigation.ClientRedirectCycle.RedirectToReferrer", + 2); // Client redirect loop is broken on 2nd pass around the loop so expect 3 // previews before previews turned off to stop loop. @@ -342,4 +340,3 @@ "Navigation.ClientRedirectCycle.RedirectToReferrer", 2); histogram_tester.ExpectTotalCount("Previews.PageEndReason.DeferAllScript", 3); } -#endif // defined(OS_ANDROID)
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js index b08315b..3e0beb3f 100644 --- a/chrome/browser/resources/local_ntp/customize.js +++ b/chrome/browser/resources/local_ntp/customize.js
@@ -2279,6 +2279,7 @@ } else { $(customize.IDS.COLORS_DEFAULT_ICON).focus(); } + event.preventDefault(); } };
diff --git a/chrome/browser/resources/settings/controls/pref_control_behavior.js b/chrome/browser/resources/settings/controls/pref_control_behavior.js index 51bbe01..8db2d75d 100644 --- a/chrome/browser/resources/settings/controls/pref_control_behavior.js +++ b/chrome/browser/resources/settings/controls/pref_control_behavior.js
@@ -37,6 +37,10 @@ } error += ' in ' + this.domHost.tagName; console.error(error); + } else if ( + this.pref.enforcement == + chrome.settingsPrivate.Enforcement.PARENT_SUPERVISED) { + console.error('PARENT_SUPERVISED is not enforced by pref controls'); } }); },
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chrome/browser/resources/settings/date_time_page/date_time_page.html index 735549d..1575327 100644 --- a/chrome/browser/resources/settings/date_time_page/date_time_page.html +++ b/chrome/browser/resources/settings/date_time_page/date_time_page.html
@@ -65,7 +65,11 @@ </settings-toggle-button> <cr-link-row class="hr" id="setDateTime" on-click="onSetDateTimeTap_" hidden$="[[!canSetDateTime_]]" - label="$i18n{setDateTime}"></cr-link-row> + label="$i18n{setDateTime}"> + <template is="dom-if" if="[[displayManagedByParentIcon_]]"> + <cr-policy-indicator indicator-type="parent"></cr-policy-indicator> + </template> + </cr-link-row> </div> <template is="dom-if" route-path="/dateTime/timeZone"> <settings-subpage data-route="DATETIME_TIMEZONE_SUBPAGE"
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.js b/chrome/browser/resources/settings/date_time_page/date_time_page.js index 186c536e..f5f8a8f 100644 --- a/chrome/browser/resources/settings/date_time_page/date_time_page.js +++ b/chrome/browser/resources/settings/date_time_page/date_time_page.js
@@ -58,6 +58,17 @@ /** @private */ isChild_: {type: Boolean, value: loadTimeData.getBoolean('isChild')}, + + /** + * Whether the icon informing that this action is managed by a parent is + * displayed. + * @private + */ + displayManagedByParentIcon_: { + type: Boolean, + value: loadTimeData.getBoolean('isChild') && + loadTimeData.getBoolean('timeActionsProtectedForChild') + }, }, /** @override */
diff --git a/chrome/browser/resources/settings/internet_page/BUILD.gn b/chrome/browser/resources/settings/internet_page/BUILD.gn index ed2f559..0dde307 100644 --- a/chrome/browser/resources/settings/internet_page/BUILD.gn +++ b/chrome/browser/resources/settings/internet_page/BUILD.gn
@@ -68,7 +68,7 @@ "..:route", "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior", "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types", - "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior", + "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior_mojo", "//ui/webui/resources/js:assert", "//ui/webui/resources/js:i18n_behavior", ] @@ -96,7 +96,7 @@ ":internet_page_browser_proxy", "..:route", "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior", - "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior", + "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior_mojo", "//ui/webui/resources/js:assert", "//ui/webui/resources/js:i18n_behavior", "//ui/webui/resources/js/chromeos:onc_mojo", @@ -123,7 +123,6 @@ deps = [ "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior", "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types", - "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior", "//ui/webui/resources/js:assert", "//ui/webui/resources/js/chromeos:onc_mojo", ] @@ -133,7 +132,7 @@ js_library("network_summary_item") { deps = [ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types", - "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior", + "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior_mojo", "//ui/webui/resources/js:assert", "//ui/webui/resources/js:i18n_behavior", "//ui/webui/resources/js/chromeos:onc_mojo",
diff --git a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html index ccac30a..b0d29715 100644 --- a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html +++ b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
@@ -36,7 +36,7 @@ <div class="list-item"> <cr-link-row embedded label="[[getNetworkDisplayName_(item)]]" on-click="fireShowDetails_"> - <template is="dom-if" if="[[isPolicySourceMojo(item.source))]]"> + <template is="dom-if" if="[[isPolicySource(item.source))]]"> <cr-policy-indicator on-click="doNothing_" indicator-type="[[getIndicatorTypeForSource(item.source)]]"> </cr-policy-indicator> @@ -60,7 +60,7 @@ <div class="list-item"> <cr-link-row embedded label="[[getNetworkDisplayName_(item)]]" on-click="fireShowDetails_"> - <template is="dom-if" if="[[isPolicySourceMojo(item.source))]]"> + <template is="dom-if" if="[[isPolicySource(item.source))]]"> <cr-policy-indicator on-click="doNothing_" indicator-type="[[getIndicatorTypeForSource(item.source)]]"> </cr-policy-indicator>
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.html b/chrome/browser/resources/settings/internet_page/internet_subpage.html index dae41691..2f61b3f 100644 --- a/chrome/browser/resources/settings/internet_page/internet_subpage.html +++ b/chrome/browser/resources/settings/internet_page/internet_subpage.html
@@ -5,6 +5,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html"> <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html"> <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html"> +<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior_mojo.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/chromeos/onc_mojo.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html">
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.js b/chrome/browser/resources/settings/internet_page/internet_subpage.js index 2ff0dc08..c5ad6a0 100644 --- a/chrome/browser/resources/settings/internet_page/internet_subpage.js +++ b/chrome/browser/resources/settings/internet_page/internet_subpage.js
@@ -16,7 +16,7 @@ behaviors: [ CrNetworkListenerBehavior, - CrPolicyNetworkBehavior, + CrPolicyNetworkBehaviorMojo, settings.RouteObserverBehavior, I18nBehavior, ], @@ -577,7 +577,7 @@ */ isBlockedByPolicy_: function(state) { if (state.type != mojom.NetworkType.kWiFi || - this.isPolicySourceMojo(state.source) || !this.globalPolicy) { + this.isPolicySource(state.source) || !this.globalPolicy) { return false; } return !!this.globalPolicy.AllowOnlyPolicyNetworksToConnect ||
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.html b/chrome/browser/resources/settings/internet_page/network_summary.html index 1dfcd0b..2ceba97 100644 --- a/chrome/browser/resources/settings/internet_page/network_summary.html +++ b/chrome/browser/resources/settings/internet_page/network_summary.html
@@ -1,7 +1,6 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_listener_behavior.html"> -<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html"> <link rel="import" href="chrome://resources/html/chromeos/onc_mojo.html"> <link rel="import" href="network_summary_item.html">
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.js b/chrome/browser/resources/settings/internet_page/network_summary.js index d8a2a016..67ed004 100644 --- a/chrome/browser/resources/settings/internet_page/network_summary.js +++ b/chrome/browser/resources/settings/internet_page/network_summary.js
@@ -16,7 +16,6 @@ behaviors: [ CrNetworkListenerBehavior, - CrPolicyNetworkBehavior, ], properties: {
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chrome/browser/resources/settings/internet_page/network_summary_item.html index 3574931d..5b26c96 100644 --- a/chrome/browser/resources/settings/internet_page/network_summary_item.html +++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -6,6 +6,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html"> <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html"> +<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior_mojo.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/chromeos/onc_mojo.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> @@ -59,7 +60,7 @@ </template> <template is="dom-if" if="[[showPolicyIndicator_(activeNetworkState)]]"> - <cr-policy-indicator indicator-type="[[getIndicatorTypeForSourceMojo( + <cr-policy-indicator indicator-type="[[getIndicatorTypeForSource( activeNetworkState.source)]]" on-click="doNothing_"> </cr-policy-indicator> </template>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.js b/chrome/browser/resources/settings/internet_page/network_summary_item.js index 8f37d8dc..12ba1e3 100644 --- a/chrome/browser/resources/settings/internet_page/network_summary_item.js +++ b/chrome/browser/resources/settings/internet_page/network_summary_item.js
@@ -16,7 +16,10 @@ Polymer({ is: 'network-summary-item', - behaviors: [CrPolicyNetworkBehavior, I18nBehavior], + behaviors: [ + CrPolicyNetworkBehaviorMojo, + I18nBehavior, + ], properties: { /** @@ -153,7 +156,7 @@ return (activeNetworkState !== undefined && OncMojo.connectionStateIsConnected( activeNetworkState.connectionState)) || - this.isPolicySourceMojo(activeNetworkState.source); + this.isPolicySource(activeNetworkState.source); }, /**
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.html b/chrome/browser/resources/settings/people_page/lock_screen.html index a16743f6..56fa177 100644 --- a/chrome/browser/resources/settings/people_page/lock_screen.html +++ b/chrome/browser/resources/settings/people_page/lock_screen.html
@@ -66,12 +66,6 @@ label="$i18n{enableScreenlock}"> </settings-toggle-button> - <settings-toggle-button id="enableLockScreenMediaControls" - hidden="[[!lockScreenMediaControlsPreferenceEnabled_]]" - pref="{{prefs.ash.lock_screen_media_controls_enabled}}" - label="$i18n{lockScreenMediaControls}"> - </settings-toggle-button> - <template is="dom-if" if="[[quickUnlockEnabled_]]"> <div id="lockOptionsDiv"> <div class="settings-box">
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.js b/chrome/browser/resources/settings/people_page/lock_screen.js index b2f7116ce..f0584fe 100644 --- a/chrome/browser/resources/settings/people_page/lock_screen.js +++ b/chrome/browser/resources/settings/people_page/lock_screen.js
@@ -130,19 +130,6 @@ readOnly: true, }, - /** - * Whether the lock screen media controls preference is enabled by the - * feature flag. - * @private - */ - lockScreenMediaControlsPreferenceEnabled_: { - type: Boolean, - value: function() { - return loadTimeData.getBoolean('lockScreenMediaControlsEnabled'); - }, - readOnly: true, - }, - /** @private */ showPasswordPromptDialog_: Boolean,
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request.cc b/chrome/browser/safe_browsing/download_protection/download_item_request.cc index 4690ae19..40b7f26 100644 --- a/chrome/browser/safe_browsing/download_protection/download_item_request.cc +++ b/chrome/browser/safe_browsing/download_protection/download_item_request.cc
@@ -17,6 +17,9 @@ std::string GetFileContentsBlocking(base::FilePath path) { base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); + if (!file.IsValid()) + return ""; + int64_t file_size = file.GetLength(); std::string contents; contents.resize(file_size); @@ -38,7 +41,10 @@ DownloadItemRequest::DownloadItemRequest(download::DownloadItem* item, BinaryUploadService::Callback callback) - : Request(std::move(callback)), item_(item), weakptr_factory_(this) { + : Request(std::move(callback)), + item_(item), + download_item_renamed_(false), + weakptr_factory_(this) { item_->AddObserver(this); } @@ -54,18 +60,38 @@ return; } - base::PostTaskAndReplyWithResult( - FROM_HERE, - {base::ThreadPool(), base::TaskPriority::USER_VISIBLE, base::MayBlock()}, - base::BindOnce(&GetFileContentsBlocking, item_->GetFullPath()), - base::BindOnce(&DownloadItemRequest::OnGotFileContents, - weakptr_factory_.GetWeakPtr(), std::move(callback))); + pending_callbacks_.push_back(std::move(callback)); + + if (download_item_renamed_) + RunPendingGetFileContentsCallbacks(); +} + +void DownloadItemRequest::RunPendingGetFileContentsCallbacks() { + for (auto it = pending_callbacks_.begin(); it != pending_callbacks_.end(); + it++) { + base::PostTaskAndReplyWithResult( + FROM_HERE, + {base::ThreadPool(), base::TaskPriority::USER_VISIBLE, + base::MayBlock()}, + base::BindOnce(&GetFileContentsBlocking, item_->GetFullPath()), + base::BindOnce(&DownloadItemRequest::OnGotFileContents, + weakptr_factory_.GetWeakPtr(), std::move(*it))); + } + + pending_callbacks_.clear(); } size_t DownloadItemRequest::GetFileSize() { return item_ == nullptr ? 0 : item_->GetTotalBytes(); } +void DownloadItemRequest::OnDownloadUpdated(download::DownloadItem* download) { + if (download == item_ && item_->GetFullPath() == item_->GetTargetFilePath()) { + download_item_renamed_ = true; + RunPendingGetFileContentsCallbacks(); + } +} + void DownloadItemRequest::OnDownloadDestroyed( download::DownloadItem* download) { if (download == item_)
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request.h b/chrome/browser/safe_browsing/download_protection/download_item_request.h index 1ff518b..2f28b2e 100644 --- a/chrome/browser/safe_browsing/download_protection/download_item_request.h +++ b/chrome/browser/safe_browsing/download_protection/download_item_request.h
@@ -33,15 +33,27 @@ // download::DownloadItem::Observer implementation. void OnDownloadDestroyed(download::DownloadItem* download) override; + void OnDownloadUpdated(download::DownloadItem* download) override; private: void OnGotFileContents(base::OnceCallback<void(const std::string&)> callback, const std::string& contents); + // Calls to GetFileContents can be deferred if the download item is not yet + // renamed to its final location. When ready, this method runs those + // callbacks. + void RunPendingGetFileContentsCallbacks(); + // Pointer the download item for upload. This must be accessed only the UI - // thread. + // thread. Unowned. download::DownloadItem* item_; + // Whether the download item has been renamed to its final destination yet. + bool download_item_renamed_; + + // All pending callbacks to GetFileContents before the download item is ready. + std::vector<base::OnceCallback<void(const std::string&)>> pending_callbacks_; + base::WeakPtrFactory<DownloadItemRequest> weakptr_factory_; }; } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc new file mode 100644 index 0000000..9a11b5d5 --- /dev/null +++ b/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc
@@ -0,0 +1,78 @@ +// Copyright 2019 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/safe_browsing/download_protection/download_item_request.h" + +#include "base/bind_helpers.h" +#include "base/files/scoped_temp_dir.h" +#include "components/download/public/common/mock_download_item.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace safe_browsing { + +using ::testing::Return; +using ::testing::ReturnRef; + +class DownloadItemRequestTest : public ::testing::Test { + public: + DownloadItemRequestTest() : item_(), request_(&item_, base::DoNothing()) {} + + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + download_path_ = temp_dir_.GetPath().AppendASCII("download_location"); + download_temporary_path_ = + temp_dir_.GetPath().AppendASCII("temporary_location"); + + base::File file(download_path_, + base::File::FLAG_CREATE | base::File::FLAG_WRITE); + ASSERT_TRUE(file.IsValid()); + + download_contents_ = "download contents"; + file.Write(0, download_contents_.c_str(), download_contents_.size()); + file.Close(); + + ON_CALL(item_, GetTotalBytes()) + .WillByDefault(Return(download_contents_.size())); + ON_CALL(item_, GetTargetFilePath()) + .WillByDefault(ReturnRef(download_path_)); + } + + protected: + content::TestBrowserThreadBundle thread_bundle_; + download::MockDownloadItem item_; + DownloadItemRequest request_; + base::ScopedTempDir temp_dir_; + base::FilePath download_path_; + base::FilePath download_temporary_path_; + std::string download_contents_; +}; + +TEST_F(DownloadItemRequestTest, GetsSize) { + EXPECT_EQ(request_.GetFileSize(), download_contents_.size()); +} + +TEST_F(DownloadItemRequestTest, GetsContentsWaitsUntilRename) { + ON_CALL(item_, GetFullPath()) + .WillByDefault(ReturnRef(download_temporary_path_)); + + std::string download_contents = ""; + request_.GetFileContents(base::BindOnce( + [](std::string* target_contents, const std::string& contents) { + *target_contents = contents; + }, + &download_contents)); + content::RunAllTasksUntilIdle(); + EXPECT_EQ(download_contents, ""); + + ON_CALL(item_, GetFullPath()).WillByDefault(ReturnRef(download_path_)); + item_.NotifyObserversDownloadUpdated(); + + content::RunAllTasksUntilIdle(); + EXPECT_EQ(download_contents, "download contents"); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/sessions/session_service_unittest.cc b/chrome/browser/sessions/session_service_unittest.cc index 855909b9..ea3fd13e 100644 --- a/chrome/browser/sessions/session_service_unittest.cc +++ b/chrome/browser/sessions/session_service_unittest.cc
@@ -35,6 +35,7 @@ #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" +#include "components/sessions/content/content_serialized_navigation_builder.h" #include "components/sessions/content/content_test_helper.h" #include "components/sessions/core/serialized_navigation_entry_test_helper.h" #include "components/sessions/core/session_command.h" @@ -910,26 +911,30 @@ SessionID tab_id = SessionID::NewUnique(); ASSERT_NE(window_id, tab_id); - // Create a page state representing a HTTP body without posted passwords. - content::PageState page_state = - content::PageState::CreateForTesting(GURL(), false, "data", NULL); - // Create a TabNavigation containing page_state and representing a POST // request. + std::string post_data = "data"; + std::unique_ptr<content::NavigationEntry> entry1 = + content::NavigationEntry::Create(); + entry1->SetURL(GURL("http://google.com")); + entry1->SetTitle(base::UTF8ToUTF16("title1")); + entry1->SetHasPostData(true); + entry1->SetPostData(network::ResourceRequestBody::CreateFromBytes( + post_data.data(), post_data.size())); SerializedNavigationEntry nav1 = - ContentTestHelper::CreateNavigation("http://google.com", "title"); - SerializedNavigationEntryTestHelper::SetEncodedPageState( - page_state.ToEncodedData(), &nav1); - SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1); - nav1.set_index(0); + sessions::ContentSerializedNavigationBuilder::FromNavigationEntry( + 0 /* == index*/, entry1.get()); // Create a TabNavigation containing page_state and representing a normal // request. + std::unique_ptr<content::NavigationEntry> entry2 = + content::NavigationEntry::Create(); + entry2->SetURL(GURL("http://google.com/nopost")); + entry2->SetTitle(base::UTF8ToUTF16("title2")); + entry2->SetHasPostData(false); SerializedNavigationEntry nav2 = - ContentTestHelper::CreateNavigation("http://google.com/nopost", "title"); - SerializedNavigationEntryTestHelper::SetEncodedPageState( - page_state.ToEncodedData(), &nav2); - nav2.set_index(1); + sessions::ContentSerializedNavigationBuilder::FromNavigationEntry( + 1 /* == index*/, entry2.get()); helper_.PrepareTabInWindow(window_id, tab_id, 0, true); UpdateNavigation(window_id, tab_id, nav1, true);
diff --git a/chrome/browser/sharing/sharing_ui_controller.cc b/chrome/browser/sharing/sharing_ui_controller.cc index 89f16e5b..34cc0b6 100644 --- a/chrome/browser/sharing/sharing_ui_controller.cc +++ b/chrome/browser/sharing/sharing_ui_controller.cc
@@ -87,6 +87,11 @@ UpdateIcon(); } +void SharingUiController::MaybeShowErrorDialog() { + if (send_failed_ && web_contents_ == GetCurrentWebContents(web_contents_)) + ShowNewDialog(); +} + void SharingUiController::SendMessageToDevice( const syncer::DeviceInfo& device, chrome_browser_sharing::SharingMessage sharing_message) { @@ -110,9 +115,6 @@ is_loading_ = false; send_failed_ = result != SharingSendMessageResult::kSuccessful; UpdateIcon(); - - if (send_failed_ && web_contents_ == GetCurrentWebContents(web_contents_)) - ShowNewDialog(); } void SharingUiController::UpdateAndShowDialog() {
diff --git a/chrome/browser/sharing/sharing_ui_controller.h b/chrome/browser/sharing/sharing_ui_controller.h index 235f98f..c5fe821 100644 --- a/chrome/browser/sharing/sharing_ui_controller.h +++ b/chrome/browser/sharing/sharing_ui_controller.h
@@ -89,6 +89,8 @@ devices_ = std::move(devices); } + void MaybeShowErrorDialog(); + protected: virtual SharingDialog* DoShowDialog(BrowserWindow* window) = 0;
diff --git a/chrome/browser/supervised_user/logged_in_user_mixin.cc b/chrome/browser/supervised_user/logged_in_user_mixin.cc index cb69584..bf54e04c 100644 --- a/chrome/browser/supervised_user/logged_in_user_mixin.cc +++ b/chrome/browser/supervised_user/logged_in_user_mixin.cc
@@ -38,12 +38,12 @@ LoggedInUserMixin::~LoggedInUserMixin() = default; -void LoggedInUserMixin::LogInUser() { +void LoggedInUserMixin::LogInUser(bool issue_any_scope_token) { UserContext user_context = LoginManagerMixin::CreateDefaultUserContext(user_); if (user_.user_type == user_manager::USER_TYPE_CHILD) { fake_gaia_.SetupFakeGaiaForChildUser( user_.account_id.GetUserEmail(), user_.account_id.GetGaiaId(), - FakeGaiaMixin::kFakeRefreshToken, false /*issue_any_scope_token*/); + FakeGaiaMixin::kFakeRefreshToken, issue_any_scope_token); } else { fake_gaia_.SetupFakeGaiaForLogin(user_.account_id.GetUserEmail(), user_.account_id.GetGaiaId(), @@ -53,4 +53,8 @@ login_manager_.LoginAndWaitForActiveSession(user_context); } +void LoggedInUserMixin::set_should_launch_browser(bool value) { + login_manager_.set_should_launch_browser(value); +} + } // namespace chromeos
diff --git a/chrome/browser/supervised_user/logged_in_user_mixin.h b/chrome/browser/supervised_user/logged_in_user_mixin.h index ddfcaf5..6809cf9 100644 --- a/chrome/browser/supervised_user/logged_in_user_mixin.h +++ b/chrome/browser/supervised_user/logged_in_user_mixin.h
@@ -27,7 +27,16 @@ net::EmbeddedTestServer* embedded_test_server); ~LoggedInUserMixin(); - void LogInUser(); + // Log in as regular or child account depending on the |type| argument passed + // to the constructor. + // * If |issue_any_scope_token|, FakeGaiaMixin will issue a special all-access + // token associated with the test refresh token. Only matters for child login. + void LogInUser(bool issue_any_scope_token = false); + + // By default, LoginManagerMixin will set up user session manager not to + // launch browser as part of user session setup - use this to override that + // behavior. + void set_should_launch_browser(bool value); private: LoginManagerMixin::TestUserInfo user_;
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index e54bfc98..b70f805 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -50,7 +50,6 @@ #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h" -#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h" #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_features.h" @@ -444,13 +443,6 @@ return PrefServiceSyncableFromProfile(profile_) ->GetSyncableService(syncer::PRIORITY_PREFERENCES) ->AsWeakPtr(); - case syncer::AUTOFILL_WALLET_METADATA: - if (profile_web_data_service_) { - return autofill::AutofillWalletMetadataSyncableService:: - FromWebDataService(profile_web_data_service_.get()) - ->AsWeakPtr(); - } - return nullptr; case syncer::SEARCH_ENGINES: return GetWeakPtrOrNull( TemplateURLServiceFactory::GetForProfile(profile_));
diff --git a/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc b/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc index 8f4764f..cb4b37fee 100644 --- a/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc
@@ -25,7 +25,7 @@ }; // crbug.com/997984 -#if defined(MEMORY_SANITIZER) +#if defined(MEMORY_SANITIZER) || defined(ADDRESS_SANITIZER) #define MAYBE_StartWithNoApps DISABLED_StartWithNoApps #define MAYBE_StartWithSomeLegacyApps DISABLED_StartWithSomeLegacyApps #define MAYBE_StartWithSomePlatformApps DISABLED_StartWithSomePlatformApps
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc index 603892c..933d6f9 100644 --- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -611,7 +611,14 @@ // If the server sends the same cards and addresses again, they should not // change on the client. We should also not overwrite existing metadata. -IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, SameUpdatesAreIgnored) { +// Flaky on ASan/TSan only. http://crbug.com/997912 +#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) +#define MAYBE_SameUpdatesAreIgnored DISABLED_SameUpdatesAreIgnored +#else +#define MAYBE_SameUpdatesAreIgnored SameUpdatesAreIgnored +#endif +IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, + MAYBE_SameUpdatesAreIgnored) { GetFakeServer()->SetWalletData( {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001", kDefaultBillingAddressID),
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index aa26cce..60410fc 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -929,10 +929,8 @@ "global_error/global_error_service.h", "global_error/global_error_service_factory.cc", "global_error/global_error_service_factory.h", - "global_media_controls/media_dialog_controller.cc", - "global_media_controls/media_dialog_controller.h", - "global_media_controls/media_dialog_controller_delegate.cc", - "global_media_controls/media_dialog_controller_delegate.h", + "global_media_controls/media_dialog_delegate.cc", + "global_media_controls/media_dialog_delegate.h", "global_media_controls/media_toolbar_button_controller.cc", "global_media_controls/media_toolbar_button_controller.h", "global_media_controls/media_toolbar_button_controller_delegate.cc", @@ -2890,8 +2888,6 @@ "views/overlay/back_to_tab_image_button.h", "views/overlay/close_image_button.cc", "views/overlay/close_image_button.h", - "views/overlay/mute_image_button.cc", - "views/overlay/mute_image_button.h", "views/overlay/overlay_window_views.cc", "views/overlay/overlay_window_views.h", "views/overlay/playback_image_button.cc", @@ -3212,8 +3208,6 @@ if (is_linux) { sources += [ - "views/frame/browser_command_handler_linux.cc", - "views/frame/browser_command_handler_linux.h", "views/process_singleton_dialog_linux.cc", "views/status_icons/status_tray_linux.cc", "views/status_icons/status_tray_linux.h",
diff --git a/chrome/browser/ui/android/overlay/overlay_window_android.h b/chrome/browser/ui/android/overlay/overlay_window_android.h index 794be57..44b8d24 100644 --- a/chrome/browser/ui/android/overlay/overlay_window_android.h +++ b/chrome/browser/ui/android/overlay/overlay_window_android.h
@@ -62,7 +62,6 @@ void UpdateVideoSize(const gfx::Size& natural_size) override; void SetPlaybackState(PlaybackState playback_state) override {} void SetAlwaysHidePlayPauseButton(bool is_visible) override {} - void SetMutedState(MutedState muted_state) override {} void SetSkipAdButtonVisibility(bool is_visible) override {} void SetNextTrackButtonVisibility(bool is_visible) override {} void SetPreviousTrackButtonVisibility(bool is_visible) override {}
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_controller.cc b/chrome/browser/ui/global_media_controls/media_dialog_controller.cc deleted file mode 100644 index 762d71c..0000000 --- a/chrome/browser/ui/global_media_controls/media_dialog_controller.cc +++ /dev/null
@@ -1,115 +0,0 @@ -// Copyright 2019 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/global_media_controls/media_dialog_controller.h" - -#include "base/bind.h" -#include "base/containers/adapters.h" -#include "chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h" -#include "components/media_message_center/media_notification_item.h" -#include "services/media_session/public/mojom/constants.mojom.h" -#include "services/service_manager/public/cpp/connector.h" - -using media_session::mojom::MediaSessionAction; - -MediaDialogController::MediaDialogController( - service_manager::Connector* connector, - MediaDialogControllerDelegate* delegate) - : connector_(connector), delegate_(delegate) { - DCHECK(delegate_); -} - -MediaDialogController::~MediaDialogController() = default; - -void MediaDialogController::Initialize() { - // |connector| can be null in tests. - if (!connector_) - return; - - // Connect to the controller manager so we can create media controllers for - // media sessions. - connector_->Connect(media_session::mojom::kServiceName, - controller_manager_remote_.BindNewPipeAndPassReceiver()); - - // Connect to receive audio focus events. - connector_->Connect(media_session::mojom::kServiceName, - audio_focus_remote_.BindNewPipeAndPassReceiver()); - audio_focus_remote_->AddObserver( - audio_focus_observer_receiver_.BindNewPipeAndPassRemote()); - - audio_focus_remote_->GetFocusRequests( - base::BindOnce(&MediaDialogController::OnReceivedAudioFocusRequests, - weak_ptr_factory_.GetWeakPtr())); -} - -void MediaDialogController::OnFocusGained( - media_session::mojom::AudioFocusRequestStatePtr session) { - const std::string id = session->request_id->ToString(); - - // If we have an existing unfrozen item then this is a duplicate call and - // we should ignore it. - auto it = sessions_.find(id); - if (it != sessions_.end() && !it->second.frozen()) - return; - - mojo::Remote<media_session::mojom::MediaController> controller; - - // |controller_manager_remote_| may be null in tests where connector is - // unavailable. - if (controller_manager_remote_) { - controller_manager_remote_->CreateMediaControllerForSession( - controller.BindNewPipeAndPassReceiver(), *session->request_id); - } - - if (it != sessions_.end()) { - // If the notification was previously frozen then we should reset the - // controller because the mojo pipe would have been reset. - it->second.SetController(std::move(controller), - std::move(session->session_info)); - } else { - sessions_.emplace( - std::piecewise_construct, std::forward_as_tuple(id), - std::forward_as_tuple( - this, id, session->source_name.value_or(std::string()), - std::move(controller), std::move(session->session_info))); - } -} - -void MediaDialogController::OnFocusLost( - media_session::mojom::AudioFocusRequestStatePtr session) { - auto it = sessions_.find(session->request_id->ToString()); - if (it == sessions_.end()) - return; - - it->second.Freeze(); -} - -void MediaDialogController::ShowNotification(const std::string& id) { - base::WeakPtr<media_message_center::MediaNotificationItem> item; - - auto it = sessions_.find(id); - if (it != sessions_.end()) - item = it->second.GetWeakPtr(); - - delegate_->ShowMediaSession(id, item); -} - -void MediaDialogController::HideNotification(const std::string& id) { - delegate_->HideMediaSession(id); -} - -void MediaDialogController::RemoveItem(const std::string& id) { - sessions_.erase(id); -} - -scoped_refptr<base::SequencedTaskRunner> MediaDialogController::GetTaskRunner() - const { - return task_runner_for_testing_; -} - -void MediaDialogController::OnReceivedAudioFocusRequests( - std::vector<media_session::mojom::AudioFocusRequestStatePtr> sessions) { - for (auto& session : sessions) - OnFocusGained(std::move(session)); -}
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_controller.h b/chrome/browser/ui/global_media_controls/media_dialog_controller.h deleted file mode 100644 index a5c13b4..0000000 --- a/chrome/browser/ui/global_media_controls/media_dialog_controller.h +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2019 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_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_H_ -#define CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_H_ - -#include <vector> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "components/media_message_center/media_notification_controller.h" -#include "mojo/public/cpp/bindings/receiver.h" -#include "mojo/public/cpp/bindings/remote.h" -#include "services/media_session/public/mojom/audio_focus.mojom.h" -#include "services/media_session/public/mojom/media_controller.mojom.h" - -namespace media_message_center { -class MediaNotificationItem; -} // namespace media_message_center - -namespace service_manager { -class Connector; -} // namespace service_manager - -class MediaDialogControllerDelegate; - -// Controller for the MediaDialogView that updates the view when the active -// media session changes. -class MediaDialogController - : public media_session::mojom::AudioFocusObserver, - public media_message_center::MediaNotificationController { - public: - MediaDialogController(service_manager::Connector* connector, - MediaDialogControllerDelegate* delegate); - ~MediaDialogController() override; - - void Initialize(); - - // media_session::mojom::AudioFocusObserver implementation. - void OnFocusGained( - media_session::mojom::AudioFocusRequestStatePtr session) override; - void OnFocusLost( - media_session::mojom::AudioFocusRequestStatePtr session) override; - - // media_message_center::MediaNotificationController implementation. - void ShowNotification(const std::string& id) override; - void HideNotification(const std::string& id) override; - void RemoveItem(const std::string& id) override; - scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() const override; - - private: - friend class MediaDialogControllerTest; - - // Called when we receive all currently active media sessions for the audio - // focus manager. Used to initialize the list of sessions. - void OnReceivedAudioFocusRequests( - std::vector<media_session::mojom::AudioFocusRequestStatePtr> sessions); - - service_manager::Connector* const connector_; - MediaDialogControllerDelegate* const delegate_; - - // Stores a |media_message_center::MediaNotificationItem| for each media - // session keyed by its |request_id| in string format. - std::map<const std::string, media_message_center::MediaNotificationItem> - sessions_; - - mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote_; - mojo::Remote<media_session::mojom::MediaControllerManager> - controller_manager_remote_; - - // Used to receive updates to the active media controller. - mojo::Receiver<media_session::mojom::AudioFocusObserver> - audio_focus_observer_receiver_{this}; - - // Task runner used for testing. - scoped_refptr<base::SequencedTaskRunner> task_runner_for_testing_; - - base::WeakPtrFactory<MediaDialogController> weak_ptr_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(MediaDialogController); -}; - -#endif // CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_H_
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.cc b/chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.cc deleted file mode 100644 index 97d12fe..0000000 --- a/chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.cc +++ /dev/null
@@ -1,7 +0,0 @@ -// Copyright 2019 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/global_media_controls/media_dialog_controller_delegate.h" - -MediaDialogControllerDelegate::~MediaDialogControllerDelegate() = default;
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_controller_unittest.cc b/chrome/browser/ui/global_media_controls/media_dialog_controller_unittest.cc deleted file mode 100644 index 54c6acab..0000000 --- a/chrome/browser/ui/global_media_controls/media_dialog_controller_unittest.cc +++ /dev/null
@@ -1,172 +0,0 @@ -// Copyright 2019 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/global_media_controls/media_dialog_controller.h" - -#include <memory> - -#include "base/strings/utf_string_conversions.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/unguessable_token.h" -#include "chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h" -#include "components/media_message_center/media_notification_item.h" -#include "services/media_session/public/mojom/audio_focus.mojom.h" -#include "services/media_session/public/mojom/media_session.mojom.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using media_session::mojom::AudioFocusRequestState; -using media_session::mojom::AudioFocusRequestStatePtr; -using media_session::mojom::MediaSessionInfo; -using media_session::mojom::MediaSessionInfoPtr; -using testing::_; - -namespace { - -class MockMediaDialogControllerDelegate : public MediaDialogControllerDelegate { - public: - MockMediaDialogControllerDelegate() = default; - ~MockMediaDialogControllerDelegate() override = default; - - // MediaDialogControllerDelegate implementation. - MOCK_METHOD2( - ShowMediaSession, - void(const std::string& id, - base::WeakPtr<media_message_center::MediaNotificationItem> item)); - MOCK_METHOD1(HideMediaSession, void(const std::string& id)); -}; - -} // anonymous namespace - -class MediaDialogControllerTest : public testing::Test { - public: - MediaDialogControllerTest() - : task_runner_(new base::TestMockTimeTaskRunner( - base::TestMockTimeTaskRunner::Type::kStandalone)) {} - - ~MediaDialogControllerTest() override = default; - - void SetUp() override { - controller_ = std::make_unique<MediaDialogController>(nullptr, &delegate_); - controller_->task_runner_for_testing_ = task_runner_.get(); - } - - protected: - AudioFocusRequestStatePtr CreateFocusRequest(const base::UnguessableToken& id, - bool controllable) { - MediaSessionInfoPtr session_info(MediaSessionInfo::New()); - session_info->is_controllable = controllable; - - AudioFocusRequestStatePtr focus(AudioFocusRequestState::New()); - focus->request_id = id; - focus->session_info = std::move(session_info); - return focus; - } - - void SimulateFocusGained(const base::UnguessableToken& id, - bool controllable) { - controller_->OnFocusGained(CreateFocusRequest(id, controllable)); - } - - void SimulateFocusLost(const base::UnguessableToken& id) { - AudioFocusRequestStatePtr focus(AudioFocusRequestState::New()); - focus->request_id = id; - controller_->OnFocusLost(std::move(focus)); - } - - void SimulateNecessaryMetadata(const base::UnguessableToken& id) { - // In order for the MediaNotificationItem to tell the MediaDialogController - // to show a media session, that session needs a title and artist. Typically - // this would happen through the media session service, but since the - // service doesn't run for this test, we'll manually grab the - // MediaNotificationItem from the MediaDialogController and set the - // metadata. - auto item_itr = controller_->sessions_.find(id.ToString()); - ASSERT_NE(controller_->sessions_.end(), item_itr); - - media_session::MediaMetadata metadata; - metadata.title = base::ASCIIToUTF16("title"); - metadata.artist = base::ASCIIToUTF16("artist"); - item_itr->second.MediaSessionMetadataChanged(std::move(metadata)); - } - - void SimulateReceivedAudioFocusRequests( - std::vector<AudioFocusRequestStatePtr> requests) { - controller_->OnReceivedAudioFocusRequests(std::move(requests)); - } - - void SimulateFreezeTimerExpired() { - task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(2500)); - } - - bool IsSessionFrozen(const base::UnguessableToken& id) const { - auto item_itr = controller_->sessions_.find(id.ToString()); - EXPECT_NE(controller_->sessions_.end(), item_itr); - return item_itr->second.frozen(); - } - - MockMediaDialogControllerDelegate& delegate() { return delegate_; } - - private: - scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; - - MockMediaDialogControllerDelegate delegate_; - std::unique_ptr<MediaDialogController> controller_; - - DISALLOW_COPY_AND_ASSIGN(MediaDialogControllerTest); -}; - -TEST_F(MediaDialogControllerTest, ShowControllableOnGainAndHideOnLoss) { - base::UnguessableToken id = base::UnguessableToken::Create(); - - EXPECT_CALL(delegate(), ShowMediaSession(id.ToString(), _)); - - SimulateFocusGained(id, true); - SimulateNecessaryMetadata(id); - EXPECT_FALSE(IsSessionFrozen(id)); - - // Ensure that the session was shown. - testing::Mock::VerifyAndClearExpectations(&delegate()); - - EXPECT_CALL(delegate(), HideMediaSession(id.ToString())).Times(0); - SimulateFocusLost(id); - EXPECT_TRUE(IsSessionFrozen(id)); - - // Ensure that the session was not hidden. - testing::Mock::VerifyAndClearExpectations(&delegate()); - - EXPECT_CALL(delegate(), HideMediaSession(id.ToString())); - SimulateFreezeTimerExpired(); -} - -TEST_F(MediaDialogControllerTest, DoesNotShowUncontrollableSession) { - base::UnguessableToken id = base::UnguessableToken::Create(); - - EXPECT_CALL(delegate(), ShowMediaSession(_, _)).Times(0); - - SimulateFocusGained(id, false); - SimulateNecessaryMetadata(id); -} - -TEST_F(MediaDialogControllerTest, ShowsAllInitialControllableSessions) { - base::UnguessableToken controllable1_id = base::UnguessableToken::Create(); - base::UnguessableToken uncontrollable_id = base::UnguessableToken::Create(); - base::UnguessableToken controllable2_id = base::UnguessableToken::Create(); - - EXPECT_CALL(delegate(), ShowMediaSession(controllable1_id.ToString(), _)); - EXPECT_CALL(delegate(), ShowMediaSession(uncontrollable_id.ToString(), _)) - .Times(0); - EXPECT_CALL(delegate(), ShowMediaSession(controllable2_id.ToString(), _)); - - std::vector<AudioFocusRequestStatePtr> requests; - requests.push_back(CreateFocusRequest(controllable1_id, true)); - requests.push_back(CreateFocusRequest(uncontrollable_id, false)); - requests.push_back(CreateFocusRequest(controllable2_id, true)); - - SimulateReceivedAudioFocusRequests(std::move(requests)); - - SimulateNecessaryMetadata(controllable1_id); - SimulateNecessaryMetadata(uncontrollable_id); - SimulateNecessaryMetadata(controllable2_id); -}
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_delegate.cc b/chrome/browser/ui/global_media_controls/media_dialog_delegate.cc new file mode 100644 index 0000000..10cf438 --- /dev/null +++ b/chrome/browser/ui/global_media_controls/media_dialog_delegate.cc
@@ -0,0 +1,7 @@ +// Copyright 2019 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/global_media_controls/media_dialog_delegate.h" + +MediaDialogDelegate::~MediaDialogDelegate() = default;
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h b/chrome/browser/ui/global_media_controls/media_dialog_delegate.h similarity index 62% rename from chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h rename to chrome/browser/ui/global_media_controls/media_dialog_delegate.h index 3b3eca3..6188d7b 100644 --- a/chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h +++ b/chrome/browser/ui/global_media_controls/media_dialog_delegate.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 CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_DELEGATE_H_ -#define CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_DELEGATE_H_ +#ifndef CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_DELEGATE_H_ +#define CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_DELEGATE_H_ #include <string> @@ -13,9 +13,9 @@ class MediaNotificationItem; } // namespace media_message_center -// Delegate for MediaDialogController that is told when to display or hide a -// media session. -class MediaDialogControllerDelegate { +// Delegate for MediaToolbarButtonController that is told when to display or +// hide a media session. +class MediaDialogDelegate { public: virtual void ShowMediaSession( const std::string& id, @@ -23,7 +23,7 @@ virtual void HideMediaSession(const std::string& id) = 0; protected: - virtual ~MediaDialogControllerDelegate(); + virtual ~MediaDialogDelegate(); }; -#endif // CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_DELEGATE_H_ +#endif // CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_DELEGATE_H_
diff --git a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc index a0a769aa..99b8737 100644 --- a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc +++ b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc
@@ -4,18 +4,13 @@ #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h" +#include "chrome/browser/ui/global_media_controls/media_dialog_delegate.h" #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller_delegate.h" +#include "components/media_message_center/media_notification_item.h" #include "services/media_session/public/mojom/constants.mojom.h" #include "services/media_session/public/mojom/media_session.mojom.h" #include "services/service_manager/public/cpp/connector.h" -namespace { - -constexpr base::TimeDelta kHideTimerDelay = - base::TimeDelta::FromMilliseconds(2500); - -} // anonymous namespace - MediaToolbarButtonController::MediaToolbarButtonController( service_manager::Connector* connector, MediaToolbarButtonControllerDelegate* delegate) @@ -26,37 +21,161 @@ if (!connector_) return; - // Connect to the MediaControllerManager and create a MediaController that - // controls the active session so we can observe it. - media_session::mojom::MediaControllerManagerPtr controller_manager_ptr; - connector_->BindInterface(media_session::mojom::kServiceName, - mojo::MakeRequest(&controller_manager_ptr)); - controller_manager_ptr->CreateActiveMediaController( - mojo::MakeRequest(&media_controller_ptr_)); + // Connect to the controller manager so we can create media controllers for + // media sessions. + connector_->Connect(media_session::mojom::kServiceName, + controller_manager_remote_.BindNewPipeAndPassReceiver()); - // Observe the active media controller for changes to playback state and - // supported actions. - media_controller_ptr_->AddObserver( - media_controller_observer_receiver_.BindNewPipeAndPassRemote()); + // Connect to receive audio focus events. + connector_->Connect(media_session::mojom::kServiceName, + audio_focus_remote_.BindNewPipeAndPassReceiver()); + audio_focus_remote_->AddObserver( + audio_focus_observer_receiver_.BindNewPipeAndPassRemote()); + + audio_focus_remote_->GetFocusRequests(base::BindOnce( + &MediaToolbarButtonController::OnReceivedAudioFocusRequests, + weak_ptr_factory_.GetWeakPtr())); } MediaToolbarButtonController::~MediaToolbarButtonController() = default; -void MediaToolbarButtonController::MediaSessionInfoChanged( - media_session::mojom::MediaSessionInfoPtr session_info) { - if (session_info && session_info->is_controllable) { - hide_icon_timer_.Stop(); - delegate_->Enable(); - delegate_->Show(); +void MediaToolbarButtonController::OnFocusGained( + media_session::mojom::AudioFocusRequestStatePtr session) { + const std::string id = session->request_id->ToString(); + + // If we have an existing unfrozen item then this is a duplicate call and + // we should ignore it. + auto it = sessions_.find(id); + if (it != sessions_.end() && !it->second.frozen()) + return; + + mojo::Remote<media_session::mojom::MediaController> controller; + + // |controller_manager_remote_| may be null in tests where connector is + // unavailable. + if (controller_manager_remote_) { + controller_manager_remote_->CreateMediaControllerForSession( + controller.BindNewPipeAndPassReceiver(), *session->request_id); + } + + if (it != sessions_.end()) { + // If the notification was previously frozen then we should reset the + // controller because the mojo pipe would have been reset. + it->second.SetController(std::move(controller), + std::move(session->session_info)); + active_controllable_session_ids_.insert(id); + frozen_session_ids_.erase(id); + UpdateToolbarButtonState(); } else { - delegate_->Disable(); - hide_icon_timer_.Start( - FROM_HERE, kHideTimerDelay, - base::BindOnce(&MediaToolbarButtonController::OnHideTimerFired, - base::Unretained(this))); + sessions_.emplace( + std::piecewise_construct, std::forward_as_tuple(id), + std::forward_as_tuple( + this, id, session->source_name.value_or(std::string()), + std::move(controller), std::move(session->session_info))); } } -void MediaToolbarButtonController::OnHideTimerFired() { - delegate_->Hide(); +void MediaToolbarButtonController::OnFocusLost( + media_session::mojom::AudioFocusRequestStatePtr session) { + const std::string id = session->request_id->ToString(); + + auto it = sessions_.find(id); + if (it == sessions_.end()) + return; + + it->second.Freeze(); + active_controllable_session_ids_.erase(id); + frozen_session_ids_.insert(id); + UpdateToolbarButtonState(); +} + +void MediaToolbarButtonController::ShowNotification(const std::string& id) { + active_controllable_session_ids_.insert(id); + UpdateToolbarButtonState(); + + if (!dialog_delegate_) + return; + + base::WeakPtr<media_message_center::MediaNotificationItem> item; + + auto it = sessions_.find(id); + if (it != sessions_.end()) + item = it->second.GetWeakPtr(); + + dialog_delegate_->ShowMediaSession(id, item); +} + +void MediaToolbarButtonController::HideNotification(const std::string& id) { + active_controllable_session_ids_.erase(id); + frozen_session_ids_.erase(id); + UpdateToolbarButtonState(); + + if (!dialog_delegate_) + return; + + dialog_delegate_->HideMediaSession(id); +} + +scoped_refptr<base::SequencedTaskRunner> +MediaToolbarButtonController::GetTaskRunner() const { + return nullptr; +} + +void MediaToolbarButtonController::RemoveItem(const std::string& id) { + active_controllable_session_ids_.erase(id); + frozen_session_ids_.erase(id); + sessions_.erase(id); + + UpdateToolbarButtonState(); +} + +void MediaToolbarButtonController::SetDialogDelegate( + MediaDialogDelegate* delegate) { + DCHECK(!delegate || !dialog_delegate_); + dialog_delegate_ = delegate; + + UpdateToolbarButtonState(); + + if (!dialog_delegate_) + return; + + for (const std::string& id : active_controllable_session_ids_) { + base::WeakPtr<media_message_center::MediaNotificationItem> item; + + auto it = sessions_.find(id); + if (it != sessions_.end()) + item = it->second.GetWeakPtr(); + + dialog_delegate_->ShowMediaSession(id, item); + } +} + +void MediaToolbarButtonController::OnReceivedAudioFocusRequests( + std::vector<media_session::mojom::AudioFocusRequestStatePtr> sessions) { + for (auto& session : sessions) + OnFocusGained(std::move(session)); +} + +void MediaToolbarButtonController::UpdateToolbarButtonState() { + if (!active_controllable_session_ids_.empty()) { + if (delegate_display_state_ != DisplayState::kShown) { + delegate_->Enable(); + delegate_->Show(); + } + delegate_display_state_ = DisplayState::kShown; + return; + } + + if (frozen_session_ids_.empty()) { + if (delegate_display_state_ != DisplayState::kHidden) + delegate_->Hide(); + delegate_display_state_ = DisplayState::kHidden; + return; + } + + if (!dialog_delegate_) { + if (delegate_display_state_ != DisplayState::kDisabled) + delegate_->Disable(); + delegate_display_state_ = DisplayState::kDisabled; + } }
diff --git a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h index d4112bd..f639d98 100644 --- a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h +++ b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h
@@ -5,55 +5,99 @@ #ifndef CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_TOOLBAR_BUTTON_CONTROLLER_H_ #define CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_TOOLBAR_BUTTON_CONTROLLER_H_ +#include <map> +#include <string> +#include <vector> + #include "base/macros.h" -#include "base/timer/timer.h" +#include "base/memory/weak_ptr.h" +#include "components/media_message_center/media_notification_controller.h" #include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "services/media_session/public/mojom/audio_focus.mojom.h" #include "services/media_session/public/mojom/media_controller.mojom.h" +namespace media_message_center { +class MediaNotificationItem; +} // namespace media_message_center + namespace service_manager { class Connector; } // namespace service_manager +class MediaDialogDelegate; class MediaToolbarButtonControllerDelegate; // Controller for the MediaToolbarButtonView that decides when to show or hide -// the icon from the toolbar. +// the icon from the toolbar. Also passes MediaNotificationItems to the +// MediaDialogView to display. class MediaToolbarButtonController - : public media_session::mojom::MediaControllerObserver { + : public media_session::mojom::AudioFocusObserver, + public media_message_center::MediaNotificationController { public: MediaToolbarButtonController(service_manager::Connector* connector, MediaToolbarButtonControllerDelegate* delegate); ~MediaToolbarButtonController() override; - // media_session::mojom::MediaControllerObserver implementation. - void MediaSessionInfoChanged( - media_session::mojom::MediaSessionInfoPtr session_info) override; - void MediaSessionMetadataChanged( - const base::Optional<media_session::MediaMetadata>& metadata) override {} - void MediaSessionActionsChanged( - const std::vector<media_session::mojom::MediaSessionAction>& actions) - override {} - void MediaSessionChanged( - const base::Optional<base::UnguessableToken>& request_id) override {} - void MediaSessionPositionChanged( - const base::Optional<media_session::MediaPosition>& position) override {} + // media_session::mojom::AudioFocusObserver implementation. + void OnFocusGained( + media_session::mojom::AudioFocusRequestStatePtr session) override; + void OnFocusLost( + media_session::mojom::AudioFocusRequestStatePtr session) override; + + // media_message_center::MediaNotificationController implementation. + void ShowNotification(const std::string& id) override; + void HideNotification(const std::string& id) override; + void RemoveItem(const std::string& id) override; + scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() const override; + + void SetDialogDelegate(MediaDialogDelegate* delegate); private: - void OnHideTimerFired(); + friend class MediaToolbarButtonControllerTest; + + // Tracks the current display state of the toolbar button delegate. + enum class DisplayState { + kShown, + kDisabled, + kHidden, + }; + + void OnReceivedAudioFocusRequests( + std::vector<media_session::mojom::AudioFocusRequestStatePtr> sessions); + + void UpdateToolbarButtonState(); service_manager::Connector* const connector_; MediaToolbarButtonControllerDelegate* const delegate_; + MediaDialogDelegate* dialog_delegate_ = nullptr; - // We hide the toolbar button when there's no active and controllable media - // session. We use this timer to avoid flashing when a media session changes. - base::OneShotTimer hide_icon_timer_; + // The delegate starts hidden and isn't shown until media playback starts. + DisplayState delegate_display_state_ = DisplayState::kHidden; - // Tracks current media session state/metadata. - media_session::mojom::MediaControllerPtr media_controller_ptr_; + // Used to track whether there are any active controllable media sessions. If + // not, then there's nothing to show in the dialog and we can hide the toolbar + // icon. + std::unordered_set<std::string> active_controllable_session_ids_; - // Used to receive updates to the active media controller. - mojo::Receiver<media_session::mojom::MediaControllerObserver> - media_controller_observer_receiver_{this}; + // Tracks the sessions that are currently frozen. If there are only frozen + // sessions, we will disable the toolbar icon and wait to hide it. + std::unordered_set<std::string> frozen_session_ids_; + + // Stores a |media_message_center::MediaNotificationItem| for each media + // session keyed by its |request_id| in string format. + std::map<const std::string, media_message_center::MediaNotificationItem> + sessions_; + + // Connections with the media session service to listen for audio focus + // updates and control media sessions. + mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote_; + mojo::Remote<media_session::mojom::MediaControllerManager> + controller_manager_remote_; + mojo::Receiver<media_session::mojom::AudioFocusObserver> + audio_focus_observer_receiver_{this}; + + base::WeakPtrFactory<MediaToolbarButtonController> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(MediaToolbarButtonController); };
diff --git a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc index 57ab723..962b8c3 100644 --- a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc +++ b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc
@@ -6,14 +6,22 @@ #include <memory> +#include "base/strings/utf_string_conversions.h" #include "base/test/task_environment.h" +#include "base/unguessable_token.h" +#include "chrome/browser/ui/global_media_controls/media_dialog_delegate.h" #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller_delegate.h" +#include "components/media_message_center/media_notification_item.h" +#include "services/media_session/public/mojom/audio_focus.mojom.h" #include "services/media_session/public/mojom/media_session.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using media_session::mojom::AudioFocusRequestState; +using media_session::mojom::AudioFocusRequestStatePtr; using media_session::mojom::MediaSessionInfo; using media_session::mojom::MediaSessionInfoPtr; +using testing::_; namespace { @@ -30,6 +38,38 @@ MOCK_METHOD0(Disable, void()); }; +class MockMediaDialogDelegate : public MediaDialogDelegate { + public: + MockMediaDialogDelegate() = default; + ~MockMediaDialogDelegate() override { Close(); } + + void Open(MediaToolbarButtonController* controller) { + ASSERT_NE(nullptr, controller); + controller_ = controller; + controller_->SetDialogDelegate(this); + } + + void Close() { + if (!controller_) + return; + + controller_->SetDialogDelegate(nullptr); + controller_ = nullptr; + } + + // MediaDialogDelegate implementation. + MOCK_METHOD2( + ShowMediaSession, + void(const std::string& id, + base::WeakPtr<media_message_center::MediaNotificationItem> item)); + MOCK_METHOD1(HideMediaSession, void(const std::string& id)); + + private: + MediaToolbarButtonController* controller_; + + DISALLOW_COPY_AND_ASSIGN(MockMediaDialogDelegate); +}; + } // anonymous namespace class MediaToolbarButtonControllerTest : public testing::Test { @@ -45,53 +85,174 @@ } protected: - void SimulatePlayingControllableMedia() { - MediaSessionInfoPtr session_info(MediaSessionInfo::New()); - session_info->is_controllable = true; - controller_->MediaSessionInfoChanged(std::move(session_info)); - } - - void SimulateMediaStopped() { controller_->MediaSessionInfoChanged(nullptr); } - void AdvanceClockMilliseconds(int milliseconds) { task_environment_.FastForwardBy( base::TimeDelta::FromMilliseconds(milliseconds)); } + base::UnguessableToken SimulatePlayingControllableMedia() { + base::UnguessableToken id = base::UnguessableToken::Create(); + SimulateFocusGained(id, true); + SimulateNecessaryMetadata(id); + return id; + } + + AudioFocusRequestStatePtr CreateFocusRequest(const base::UnguessableToken& id, + bool controllable) { + MediaSessionInfoPtr session_info(MediaSessionInfo::New()); + session_info->is_controllable = controllable; + + AudioFocusRequestStatePtr focus(AudioFocusRequestState::New()); + focus->request_id = id; + focus->session_info = std::move(session_info); + return focus; + } + + void SimulateFocusGained(const base::UnguessableToken& id, + bool controllable) { + controller_->OnFocusGained(CreateFocusRequest(id, controllable)); + } + + void SimulateFocusLost(const base::UnguessableToken& id) { + AudioFocusRequestStatePtr focus(AudioFocusRequestState::New()); + focus->request_id = id; + controller_->OnFocusLost(std::move(focus)); + } + + void SimulateNecessaryMetadata(const base::UnguessableToken& id) { + // In order for the MediaNotificationItem to tell the + // MediaToolbarButtonController to show a media session, that session needs + // a title and artist. Typically this would happen through the media session + // service, but since the service doesn't run for this test, we'll manually + // grab the MediaNotificationItem from the MediaToolbarButtonController and + // set the metadata. + auto item_itr = controller_->sessions_.find(id.ToString()); + ASSERT_NE(controller_->sessions_.end(), item_itr); + + media_session::MediaMetadata metadata; + metadata.title = base::ASCIIToUTF16("title"); + metadata.artist = base::ASCIIToUTF16("artist"); + item_itr->second.MediaSessionMetadataChanged(std::move(metadata)); + } + + void SimulateReceivedAudioFocusRequests( + std::vector<AudioFocusRequestStatePtr> requests) { + controller_->OnReceivedAudioFocusRequests(std::move(requests)); + } + + bool IsSessionFrozen(const base::UnguessableToken& id) const { + auto item_itr = controller_->sessions_.find(id.ToString()); + EXPECT_NE(controller_->sessions_.end(), item_itr); + return item_itr->second.frozen(); + } + + void SimulateDialogOpened(MockMediaDialogDelegate* delegate) { + delegate->Open(controller_.get()); + } + MockMediaToolbarButtonControllerDelegate& delegate() { return delegate_; } private: base::test::TaskEnvironment task_environment_; - std::unique_ptr<MediaToolbarButtonController> controller_; MockMediaToolbarButtonControllerDelegate delegate_; + std::unique_ptr<MediaToolbarButtonController> controller_; DISALLOW_COPY_AND_ASSIGN(MediaToolbarButtonControllerTest); }; -TEST_F(MediaToolbarButtonControllerTest, CallsShowForControllableMedia) { +TEST_F(MediaToolbarButtonControllerTest, ShowControllableOnGainAndHideOnLoss) { + // Simulate a new active, controllable media session. EXPECT_CALL(delegate(), Show()); - SimulatePlayingControllableMedia(); + base::UnguessableToken id = SimulatePlayingControllableMedia(); + EXPECT_FALSE(IsSessionFrozen(id)); + + // Ensure that the toolbar button was shown. + testing::Mock::VerifyAndClearExpectations(&delegate()); + + // Simulate opening a MediaDialogView. + MockMediaDialogDelegate dialog_delegate; + EXPECT_CALL(dialog_delegate, ShowMediaSession(id.ToString(), _)); + SimulateDialogOpened(&dialog_delegate); + + // Ensure that the session was shown. + testing::Mock::VerifyAndClearExpectations(&dialog_delegate); + + // Simulate the active session ending. + EXPECT_CALL(dialog_delegate, HideMediaSession(id.ToString())).Times(0); + SimulateFocusLost(id); + + // Ensure that the session was frozen and not hidden. + EXPECT_TRUE(IsSessionFrozen(id)); + testing::Mock::VerifyAndClearExpectations(&dialog_delegate); + + // Once the freeze timer fires, we should hide the media session. + EXPECT_CALL(dialog_delegate, HideMediaSession(id.ToString())); + AdvanceClockMilliseconds(2500); +} + +TEST_F(MediaToolbarButtonControllerTest, DoesNotShowUncontrollableSession) { + base::UnguessableToken id = base::UnguessableToken::Create(); + + EXPECT_CALL(delegate(), Show()).Times(0); + + SimulateFocusGained(id, false); + SimulateNecessaryMetadata(id); +} + +TEST_F(MediaToolbarButtonControllerTest, ShowsAllInitialControllableSessions) { + base::UnguessableToken controllable1_id = base::UnguessableToken::Create(); + base::UnguessableToken uncontrollable_id = base::UnguessableToken::Create(); + base::UnguessableToken controllable2_id = base::UnguessableToken::Create(); + + std::vector<AudioFocusRequestStatePtr> requests; + requests.push_back(CreateFocusRequest(controllable1_id, true)); + requests.push_back(CreateFocusRequest(uncontrollable_id, false)); + requests.push_back(CreateFocusRequest(controllable2_id, true)); + + // Having active, controllable sessions should show the toolbar button. + EXPECT_CALL(delegate(), Show()); + + SimulateReceivedAudioFocusRequests(std::move(requests)); + + SimulateNecessaryMetadata(controllable1_id); + SimulateNecessaryMetadata(uncontrollable_id); + SimulateNecessaryMetadata(controllable2_id); + + testing::Mock::VerifyAndClearExpectations(&delegate()); + + // If we open a dialog, it should be told to show the controllable sessions, + // but not the uncontrollable one. + MockMediaDialogDelegate dialog_delegate; + + EXPECT_CALL(dialog_delegate, + ShowMediaSession(controllable1_id.ToString(), _)); + EXPECT_CALL(dialog_delegate, + ShowMediaSession(uncontrollable_id.ToString(), _)) + .Times(0); + EXPECT_CALL(dialog_delegate, + ShowMediaSession(controllable2_id.ToString(), _)); + SimulateDialogOpened(&dialog_delegate); } TEST_F(MediaToolbarButtonControllerTest, HidesAfterTimeoutAndShowsAgainOnPlay) { // First, show the button. EXPECT_CALL(delegate(), Show()); - SimulatePlayingControllableMedia(); + base::UnguessableToken id = SimulatePlayingControllableMedia(); testing::Mock::VerifyAndClearExpectations(&delegate()); // Then, stop playing media so the button is disabled, but hasn't been hidden // yet. EXPECT_CALL(delegate(), Disable()); EXPECT_CALL(delegate(), Hide()).Times(0); - SimulateMediaStopped(); + SimulateFocusLost(id); testing::Mock::VerifyAndClearExpectations(&delegate()); - // If the time hasn't elapsed yet, we should still not be hidden. + // If the time hasn't elapsed yet, the button should still not be hidden. EXPECT_CALL(delegate(), Hide()).Times(0); AdvanceClockMilliseconds(2400); testing::Mock::VerifyAndClearExpectations(&delegate()); - // Once the time is elapsed, we should be hidden. + // Once the time is elapsed, the button should be hidden. EXPECT_CALL(delegate(), Hide()); AdvanceClockMilliseconds(200); testing::Mock::VerifyAndClearExpectations(&delegate()); @@ -103,18 +264,37 @@ testing::Mock::VerifyAndClearExpectations(&delegate()); } +TEST_F(MediaToolbarButtonControllerTest, DoesNotDisableButtonIfDialogIsOpen) { + // First, show the button. + EXPECT_CALL(delegate(), Show()); + base::UnguessableToken id = SimulatePlayingControllableMedia(); + testing::Mock::VerifyAndClearExpectations(&delegate()); + + // Then, open a dialog. + MockMediaDialogDelegate dialog_delegate; + EXPECT_CALL(dialog_delegate, ShowMediaSession(id.ToString(), _)); + SimulateDialogOpened(&dialog_delegate); + + // Then, have the session lose focus. This should not disable the button when + // a dialog is present (since the button can still be used to close the + // dialog). + EXPECT_CALL(delegate(), Disable()).Times(0); + SimulateFocusLost(id); + testing::Mock::VerifyAndClearExpectations(&delegate()); +} + TEST_F(MediaToolbarButtonControllerTest, DoesNotHideIfMediaStartsPlayingWithinTimeout) { // First, show the button. EXPECT_CALL(delegate(), Show()); - SimulatePlayingControllableMedia(); + base::UnguessableToken id = SimulatePlayingControllableMedia(); testing::Mock::VerifyAndClearExpectations(&delegate()); // Then, stop playing media so the button is disabled, but hasn't been hidden // yet. EXPECT_CALL(delegate(), Disable()); EXPECT_CALL(delegate(), Hide()).Times(0); - SimulateMediaStopped(); + SimulateFocusLost(id); testing::Mock::VerifyAndClearExpectations(&delegate()); // If the time hasn't elapsed yet, we should still not be hidden. @@ -128,3 +308,32 @@ SimulatePlayingControllableMedia(); testing::Mock::VerifyAndClearExpectations(&delegate()); } + +TEST_F(MediaToolbarButtonControllerTest, NewMediaSessionWhileDialogOpen) { + // First, show the button. + EXPECT_CALL(delegate(), Show()); + base::UnguessableToken id = SimulatePlayingControllableMedia(); + testing::Mock::VerifyAndClearExpectations(&delegate()); + + // Then, open a dialog. + MockMediaDialogDelegate dialog_delegate; + EXPECT_CALL(dialog_delegate, ShowMediaSession(id.ToString(), _)); + SimulateDialogOpened(&dialog_delegate); + testing::Mock::VerifyAndClearExpectations(&dialog_delegate); + + // Then, have a new media session start while the dialog is opened. This + // should update the dialog. + base::UnguessableToken new_id = base::UnguessableToken::Create(); + EXPECT_CALL(dialog_delegate, ShowMediaSession(new_id.ToString(), _)); + SimulateFocusGained(new_id, true); + SimulateNecessaryMetadata(new_id); + testing::Mock::VerifyAndClearExpectations(&dialog_delegate); + + // If we close this dialog and open a new one, the new one should receive both + // media sessions immediately. + dialog_delegate.Close(); + MockMediaDialogDelegate new_dialog; + EXPECT_CALL(new_dialog, ShowMediaSession(id.ToString(), _)); + EXPECT_CALL(new_dialog, ShowMediaSession(new_id.ToString(), _)); + SimulateDialogOpened(&new_dialog); +}
diff --git a/chrome/browser/ui/views/critical_notification_bubble_view.cc b/chrome/browser/ui/views/critical_notification_bubble_view.cc index 8bedf94..a4c7c4c 100644 --- a/chrome/browser/ui/views/critical_notification_bubble_view.cc +++ b/chrome/browser/ui/views/critical_notification_bubble_view.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/chrome_typography.h" #include "chrome/browser/upgrade_detector/upgrade_detector.h" #include "chrome/common/pref_names.h" #include "chrome/grit/chromium_strings.h" @@ -23,6 +24,7 @@ #include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/controls/label.h" #include "ui/views/layout/fill_layout.h" +#include "ui/views/style/typography.h" #include "ui/views/widget/widget.h" using base::UserMetricsAction; @@ -125,15 +127,16 @@ SetLayoutManager(std::make_unique<views::FillLayout>()); - views::Label* message = new views::Label(); + auto message = std::make_unique<views::Label>( + l10n_util::GetStringUTF16(IDS_CRITICAL_NOTIFICATION_TEXT), + views::style::CONTEXT_MESSAGE_BOX_BODY_TEXT, STYLE_SECONDARY); message->SetMultiLine(true); message->SetHorizontalAlignment(gfx::ALIGN_LEFT); - message->SetText(l10n_util::GetStringUTF16(IDS_CRITICAL_NOTIFICATION_TEXT)); message->SizeToFit( ChromeLayoutProvider::Get()->GetDistanceMetric( ChromeDistanceMetric::DISTANCE_BUBBLE_PREFERRED_WIDTH) - margins().width()); - AddChildView(message); + AddChildView(std::move(message)); refresh_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kRefreshBubbleEvery),
diff --git a/chrome/browser/ui/views/frame/browser_command_handler_linux.cc b/chrome/browser/ui/views/frame/browser_command_handler_linux.cc deleted file mode 100644 index 2c4d7e85..0000000 --- a/chrome/browser/ui/views/frame/browser_command_handler_linux.cc +++ /dev/null
@@ -1,81 +0,0 @@ -// 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. - -#include "chrome/browser/ui/views/frame/browser_command_handler_linux.h" - -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/views/frame/browser_view.h" -#include "content/public/browser/navigation_controller.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/content_features.h" -#include "ui/aura/window.h" -#include "ui/events/event.h" - -BrowserCommandHandlerLinux::BrowserCommandHandlerLinux( - BrowserView* browser_view) - : browser_view_(browser_view) { - aura::Window* window = browser_view_->frame()->GetNativeWindow(); - DCHECK(window); - window->AddObserver(this); - window->AddPreTargetHandler(this); -} - -BrowserCommandHandlerLinux::~BrowserCommandHandlerLinux() { - aura::Window* window = browser_view_->frame()->GetNativeWindow(); - if (window) - RemoveObservers(window); -} - -void BrowserCommandHandlerLinux::RemoveObservers(aura::Window* window) { - window->RemoveObserver(this); - window->RemovePreTargetHandler(this); -} - -void BrowserCommandHandlerLinux::OnMouseEvent(ui::MouseEvent* event) { - // Handle standard Linux mouse buttons for going back and forward. - // Mouse press events trigger the navigations, while mouse release events are - // consumed and ignored so they aren't forwarded as unpaired events (which may - // trigger navigations as well) - bool mouse_pressed = (event->type() == ui::ET_MOUSE_PRESSED); - bool mouse_released = (event->type() == ui::ET_MOUSE_RELEASED); - if (!mouse_pressed && !mouse_released) - return; - - // If extended mouse buttons are supported handle them in the renderer. - if (base::FeatureList::IsEnabled(features::kExtendedMouseButtons)) - return; - - bool back_button_toggled = - (event->changed_button_flags() == ui::EF_BACK_MOUSE_BUTTON); - bool forward_button_toggled = - (event->changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON); - if (!back_button_toggled && !forward_button_toggled) - return; - - content::WebContents* contents = - browser_view_->browser()->tab_strip_model()->GetActiveWebContents(); - if (!contents) - return; - - // Always consume the event, whether a navigation is successful or not. - // - // TODO(mustaq): Perhaps we should mark "handled" only for successful - // navigation above but a bug in the past didn't allow it: - // https://codereview.chromium.org/2763313002/#msg19 - event->SetHandled(); - - if (!mouse_pressed) - return; - - content::NavigationController& controller = contents->GetController(); - if (back_button_toggled && controller.CanGoBack()) - controller.GoBack(); - else if (forward_button_toggled && controller.CanGoForward()) - controller.GoForward(); -} - -void BrowserCommandHandlerLinux::OnWindowDestroying(aura::Window* window) { - RemoveObservers(window); -}
diff --git a/chrome/browser/ui/views/frame/browser_command_handler_linux.h b/chrome/browser/ui/views/frame/browser_command_handler_linux.h deleted file mode 100644 index d195fa07..0000000 --- a/chrome/browser/ui/views/frame/browser_command_handler_linux.h +++ /dev/null
@@ -1,34 +0,0 @@ -// 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 CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_COMMAND_HANDLER_LINUX_H_ -#define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_COMMAND_HANDLER_LINUX_H_ - -#include "base/macros.h" -#include "ui/aura/window_observer.h" -#include "ui/events/event_handler.h" - -class BrowserView; - -class BrowserCommandHandlerLinux : public ui::EventHandler, - public aura::WindowObserver { - public: - explicit BrowserCommandHandlerLinux(BrowserView* browser_view); - ~BrowserCommandHandlerLinux() override; - - private: - void RemoveObservers(aura::Window* window); - - // ui::EventHandler: - void OnMouseEvent(ui::MouseEvent* event) override; - - // aura::WindowObserver: - void OnWindowDestroying(aura::Window* window) override; - - BrowserView* browser_view_; - - DISALLOW_COPY_AND_ASSIGN(BrowserCommandHandlerLinux); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_COMMAND_HANDLER_LINUX_H_
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc index e38037d3..fc26532 100644 --- a/chrome/browser/ui/views/frame/browser_frame.cc +++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -39,10 +39,6 @@ #include "components/user_manager/user_manager.h" #endif -#if defined(OS_LINUX) -#include "chrome/browser/ui/views/frame/browser_command_handler_linux.h" -#endif - #if defined(USE_X11) #include "ui/views/widget/desktop_aura/x11_desktop_handler.h" #endif @@ -110,11 +106,6 @@ DCHECK(non_client_view()); non_client_view()->set_context_menu_controller(this); } - -#if defined(OS_LINUX) - browser_command_handler_ = - std::make_unique<BrowserCommandHandlerLinux>(browser_view_); -#endif } int BrowserFrame::GetMinimizeButtonOffset() const {
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h index 5e7f0c87..d168479 100644 --- a/chrome/browser/ui/views/frame/browser_frame.h +++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -32,7 +32,6 @@ } namespace ui { -class EventHandler; class MenuModel; } @@ -153,8 +152,6 @@ // NativeBrowserFrame::UsesNativeSystemMenu() returns false. std::unique_ptr<views::MenuRunner> menu_runner_; - std::unique_ptr<ui::EventHandler> browser_command_handler_; - ScopedObserver<ui::MaterialDesignController, ui::MaterialDesignControllerObserver> md_observer_{this};
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc index 71dee05..1398eac2 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/views/global_media_controls/media_dialog_view.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h" #include "chrome/browser/ui/views/global_media_controls/media_notification_list_view.h" @@ -27,9 +28,11 @@ // static void MediaDialogView::ShowDialog(views::View* anchor_view, + MediaToolbarButtonController* controller, service_manager::Connector* connector) { DCHECK(!instance_); - instance_ = new MediaDialogView(anchor_view, connector); + DCHECK(controller); + instance_ = new MediaDialogView(anchor_view, controller, connector); views::Widget* widget = views::BubbleDialogDelegateView::CreateBubble(instance_); @@ -38,8 +41,10 @@ // static void MediaDialogView::HideDialog() { - if (IsShowing()) + if (IsShowing()) { + instance_->controller_->SetDialogDelegate(nullptr); instance_->GetWidget()->Close(); + } // Set |instance_| to nullptr so that |IsShowing()| returns false immediately. // We also set to nullptr in |WindowClosing()| (which happens asynchronously), @@ -77,6 +82,8 @@ views::BubbleFrameView* frame = GetBubbleFrameView(); if (frame) frame->SetCornerRadius(kMediaDialogCornerRadius); + + controller_->SetDialogDelegate(this); } gfx::Size MediaDialogView::CalculatePreferredSize() const { @@ -91,11 +98,14 @@ } MediaDialogView::MediaDialogView(views::View* anchor_view, + MediaToolbarButtonController* controller, service_manager::Connector* connector) : BubbleDialogDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), - controller_(connector, this), + controller_(controller), active_sessions_view_( - AddChildView(std::make_unique<MediaNotificationListView>())) {} + AddChildView(std::make_unique<MediaNotificationListView>())) { + DCHECK(controller_); +} MediaDialogView::~MediaDialogView() = default; @@ -104,11 +114,11 @@ set_margins(gfx::Insets()); SetLayoutManager(std::make_unique<views::FillLayout>()); - - controller_.Initialize(); } void MediaDialogView::WindowClosing() { - if (instance_ == this) + if (instance_ == this) { instance_ = nullptr; + controller_->SetDialogDelegate(nullptr); + } }
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h index 344c1851..172cc5b 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
@@ -6,8 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_VIEW_H_ #include "base/optional.h" -#include "chrome/browser/ui/global_media_controls/media_dialog_controller.h" -#include "chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h" +#include "chrome/browser/ui/global_media_controls/media_dialog_delegate.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" namespace service_manager { @@ -15,17 +14,19 @@ } // namespace service_manager class MediaNotificationListView; +class MediaToolbarButtonController; // Dialog that shows media controls that control the active media session. class MediaDialogView : public views::BubbleDialogDelegateView, - public MediaDialogControllerDelegate { + public MediaDialogDelegate { public: static void ShowDialog(views::View* anchor_view, + MediaToolbarButtonController* controller, service_manager::Connector* connector); static void HideDialog(); static bool IsShowing(); - // MediaDialogControllerDelegate implementation. + // MediaDialogDelegate implementation. void ShowMediaSession( const std::string& id, base::WeakPtr<media_message_center::MediaNotificationItem> item) override; @@ -41,6 +42,7 @@ private: explicit MediaDialogView(views::View* anchor_view, + MediaToolbarButtonController* controller, service_manager::Connector* connector); ~MediaDialogView() override; @@ -50,7 +52,7 @@ void Init() override; void WindowClosing() override; - MediaDialogController controller_; + MediaToolbarButtonController* const controller_; MediaNotificationListView* const active_sessions_view_;
diff --git a/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.cc b/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.cc index 6608f03..38db83b 100644 --- a/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.cc +++ b/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.cc
@@ -38,7 +38,7 @@ if (MediaDialogView::IsShowing()) MediaDialogView::HideDialog(); else - MediaDialogView::ShowDialog(this, connector_); + MediaDialogView::ShowDialog(this, &controller_, connector_); } void MediaToolbarButtonView::Show() {
diff --git a/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.h b/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.h index 87b9f55..4b002e3 100644 --- a/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.h +++ b/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_TOOLBAR_BUTTON_VIEW_H_ #include "base/macros.h" +#include "base/unguessable_token.h" #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h" #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller_delegate.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h" @@ -37,7 +38,7 @@ void UpdateIcon(); private: - service_manager::Connector* connector_; + service_manager::Connector* const connector_; MediaToolbarButtonController controller_; DISALLOW_COPY_AND_ASSIGN(MediaToolbarButtonView);
diff --git a/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc b/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc index eb3a907cc..d71ea49 100644 --- a/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc +++ b/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/chrome_typography.h" #include "chrome/browser/upgrade_detector/upgrade_detector.h" #include "chrome/common/pref_names.h" #include "chrome/grit/chromium_strings.h" @@ -21,6 +22,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/views/controls/label.h" #include "ui/views/layout/fill_layout.h" +#include "ui/views/style/typography.h" #include "ui/views/widget/widget.h" #include "url/gurl.h" @@ -152,15 +154,16 @@ void OutdatedUpgradeBubbleView::Init() { SetLayoutManager(std::make_unique<views::FillLayout>()); - views::Label* text_label = - new views::Label(l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_TEXT)); + auto text_label = std::make_unique<views::Label>( + l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_TEXT), + views::style::CONTEXT_MESSAGE_BOX_BODY_TEXT, STYLE_SECONDARY); text_label->SetMultiLine(true); text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); text_label->SizeToFit( ChromeLayoutProvider::Get()->GetDistanceMetric( ChromeDistanceMetric::DISTANCE_BUBBLE_PREFERRED_WIDTH) - margins().width()); - AddChildView(text_label); + AddChildView(std::move(text_label)); } OutdatedUpgradeBubbleView::OutdatedUpgradeBubbleView(
diff --git a/chrome/browser/ui/views/overlay/mute_image_button.cc b/chrome/browser/ui/views/overlay/mute_image_button.cc deleted file mode 100644 index 8c88ef08..0000000 --- a/chrome/browser/ui/views/overlay/mute_image_button.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2019 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/overlay/mute_image_button.h" - -#include "chrome/app/vector_icons/vector_icons.h" -#include "chrome/grit/generated_resources.h" -#include "components/vector_icons/vector_icons.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/vector_icons.h" - -namespace { - -const int kMuteImageSize = 22; - -constexpr SkColor kMuteIconColor = SK_ColorWHITE; - -} // namespace - -namespace views { - -MuteImageButton::MuteImageButton(ButtonListener* listener) - : ImageButton(listener), - mute_image_( - gfx::CreateVectorIcon(kTabAudioIcon, kMuteImageSize, kMuteIconColor)), - unmute_image_(gfx::CreateVectorIcon(kTabAudioMutingIcon, - kMuteImageSize, - kMuteIconColor)) { - SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER); - SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE); - - // Accessibility. - SetFocusForPlatform(); - const base::string16 mute_button_label(l10n_util::GetStringUTF16( - IDS_PICTURE_IN_PICTURE_MUTE_CONTROL_ACCESSIBLE_TEXT)); - SetAccessibleName(mute_button_label); - SetInstallFocusRingOnFocus(true); -} - -void MuteImageButton::SetMutedState( - OverlayWindowViews::MutedState muted_state) { - muted_state_ = muted_state; - switch (muted_state_) { - case OverlayWindowViews::kMuted: - SetImage(views::Button::STATE_NORMAL, unmute_image_); - SetTooltipText(l10n_util::GetStringUTF16( - IDS_PICTURE_IN_PICTURE_UNMUTE_CONTROL_TEXT)); - break; - case OverlayWindowViews::kUnmuted: - SetImage(views::Button::STATE_NORMAL, mute_image_); - SetTooltipText( - l10n_util::GetStringUTF16(IDS_PICTURE_IN_PICTURE_MUTE_CONTROL_TEXT)); - break; - case OverlayWindowViews::kNoAudio: - ToggleVisibility(false); - } - SchedulePaint(); -} - -gfx::Size MuteImageButton::GetLastVisibleSize() const { - return size().IsEmpty() ? last_visible_size_ : size(); -} - -void MuteImageButton::OnBoundsChanged(const gfx::Rect&) { - if (!size().IsEmpty()) - last_visible_size_ = size(); -} - -void MuteImageButton::ToggleVisibility(bool is_visible) { - if (muted_state_ == OverlayWindowViews::kNoAudio && is_visible) - return; - - layer()->SetVisible(is_visible); - SetEnabled(is_visible); - SetSize(is_visible ? GetLastVisibleSize() : gfx::Size()); -} - -} // namespace views
diff --git a/chrome/browser/ui/views/overlay/mute_image_button.h b/chrome/browser/ui/views/overlay/mute_image_button.h deleted file mode 100644 index c1bbcdc..0000000 --- a/chrome/browser/ui/views/overlay/mute_image_button.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2019 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_OVERLAY_MUTE_IMAGE_BUTTON_H_ -#define CHROME_BROWSER_UI_VIEWS_OVERLAY_MUTE_IMAGE_BUTTON_H_ - -#include "chrome/browser/ui/views/overlay/overlay_window_views.h" -#include "ui/views/controls/button/image_button.h" - -namespace views { - -// An image button representing a mute button. -class MuteImageButton : public views::ImageButton { - public: - explicit MuteImageButton(ButtonListener*); - ~MuteImageButton() override = default; - - // Show mute/unmute image and update tooltip based on video muted status. - void SetMutedState(OverlayWindowViews::MutedState); - - // Get button size when visible. - gfx::Size GetLastVisibleSize() const; - - // Toggle visibility. - void ToggleVisibility(bool is_visible); - - protected: - // Overridden from views::View. - void OnBoundsChanged(const gfx::Rect& previous_bounds) override; - - private: - const gfx::ImageSkia mute_image_; - const gfx::ImageSkia unmute_image_; - - OverlayWindowViews::MutedState muted_state_; - - // Last visible size of the image button. - gfx::Size last_visible_size_; - - DISALLOW_COPY_AND_ASSIGN(MuteImageButton); -}; - -} // namespace views - -#endif // CHROME_BROWSER_UI_VIEWS_OVERLAY_MUTE_IMAGE_BUTTON_H_
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc index 049a0dc..39d6339 100644 --- a/chrome/browser/ui/views/overlay/overlay_window_views.cc +++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -15,7 +15,6 @@ #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/ui/views/overlay/back_to_tab_image_button.h" #include "chrome/browser/ui/views/overlay/close_image_button.h" -#include "chrome/browser/ui/views/overlay/mute_image_button.h" #include "chrome/browser/ui/views/overlay/playback_image_button.h" #include "chrome/browser/ui/views/overlay/resize_handle_button.h" #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h" @@ -135,7 +134,6 @@ OverlayWindowViews* window = static_cast<OverlayWindowViews*>(widget_); if (window->AreControlsVisible() && (window->GetBackToTabControlsBounds().Contains(point) || - window->GetMuteControlsBounds().Contains(point) || window->GetSkipAdControlsBounds().Contains(point) || window->GetCloseControlsBounds().Contains(point) || window->GetPlayPauseControlsBounds().Contains(point) || @@ -343,7 +341,6 @@ this, vector_icons::kMediaNextTrackIcon, l10n_util::GetStringUTF16( IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT)); - auto mute_controls_view = std::make_unique<views::MuteImageButton>(this); auto skip_ad_controls_view = std::make_unique<views::SkipAdLabelButton>(this); #if defined(OS_CHROMEOS) auto resize_handle_view = std::make_unique<views::ResizeHandleButton>(this); @@ -398,12 +395,6 @@ next_track_controls_view->layer()->SetFillsBoundsOpaquely(false); next_track_controls_view->layer()->set_name("NextTrackControlsView"); - // views::View that holds the mute image button. ---------------------------- - mute_controls_view->SetPaintToLayer(ui::LAYER_TEXTURED); - mute_controls_view->layer()->SetFillsBoundsOpaquely(false); - mute_controls_view->layer()->set_name("MuteControlsView"); - mute_controls_view->SetMutedState(kNoAudio); - // views::View that holds the skip-ad label button. ------------------------- skip_ad_controls_view->SetPaintToLayer(ui::LAYER_TEXTURED); skip_ad_controls_view->layer()->SetFillsBoundsOpaquely(true); @@ -433,8 +424,6 @@ GetContentsView()->AddChildView(std::move(play_pause_controls_view)); next_track_controls_view_ = GetContentsView()->AddChildView(std::move(next_track_controls_view)); - mute_controls_view_ = - GetContentsView()->AddChildView(std::move(mute_controls_view)); skip_ad_controls_view_ = GetContentsView()->AddChildView(std::move(skip_ad_controls_view)); #if defined(OS_CHROMEOS) @@ -499,7 +488,6 @@ // We need to do more than usual visibility change because otherwise control // is accessible via accessibility tools. - mute_controls_view_->ToggleVisibility(is_visible); skip_ad_controls_view_->ToggleVisibility(is_visible && show_skip_ad_button_); #if defined(OS_CHROMEOS) @@ -545,7 +533,6 @@ // #2 Previous track // #3 Play/Pause // #4 Next track - // #5 Mute std::vector<views::ImageButton*> visible_controls_views; visible_controls_views.push_back(back_to_tab_controls_view_); if (show_previous_track_button_) @@ -554,8 +541,6 @@ visible_controls_views.push_back(play_pause_controls_view_); if (show_next_track_button_) visible_controls_views.push_back(next_track_controls_view_); - if (show_mute_button_) - visible_controls_views.push_back(mute_controls_view_); int mid_window_x = GetBounds().size().width() / 2; int primary_control_y = GetBounds().size().height() - @@ -640,36 +625,6 @@ secondary_control_y)); return; } - case 5: { - /* | [ ] [ ] [ ] [ ] [ ] | */ - visible_controls_views[0]->SetSize(kSecondaryControlSize); - visible_controls_views[0]->SetPosition( - gfx::Point(mid_window_x - kPrimaryControlSize.width() / 2 - - kControlMargin * 2 - kSecondaryControlSize.width() * 2, - secondary_control_y)); - - visible_controls_views[1]->SetSize(kSecondaryControlSize); - visible_controls_views[1]->SetPosition( - gfx::Point(mid_window_x - kPrimaryControlSize.width() / 2 - - kControlMargin - kSecondaryControlSize.width(), - secondary_control_y)); - - visible_controls_views[2]->SetSize(kPrimaryControlSize); - visible_controls_views[2]->SetPosition(gfx::Point( - mid_window_x - kPrimaryControlSize.width() / 2, primary_control_y)); - - visible_controls_views[3]->SetSize(kSecondaryControlSize); - visible_controls_views[3]->SetPosition(gfx::Point( - mid_window_x + kPrimaryControlSize.width() / 2 + kControlMargin, - secondary_control_y)); - - visible_controls_views[4]->SetSize(kSecondaryControlSize); - visible_controls_views[4]->SetPosition( - gfx::Point(mid_window_x + kPrimaryControlSize.width() / 2 + - kControlMargin * 2 + kSecondaryControlSize.width(), - secondary_control_y)); - return; - } } DCHECK(false); } @@ -754,16 +709,6 @@ UpdateControlsBounds(); } -void OverlayWindowViews::SetMutedState(MutedState muted_state) { - if (muted_state_for_testing_ == muted_state) - return; - - muted_state_for_testing_ = muted_state; - show_mute_button_ = (muted_state != kNoAudio); - mute_controls_view_->SetMutedState(muted_state); - UpdateControlsBounds(); -} - void OverlayWindowViews::SetSkipAdButtonVisibility(bool is_visible) { show_skip_ad_button_ = is_visible; } @@ -950,10 +895,6 @@ controller_->CloseAndFocusInitiator(); RecordTapGesture(OverlayWindowControl::kBackToTab); event->SetHandled(); - } else if (GetMuteControlsBounds().Contains(event->location())) { - ToggleMute(); - RecordTapGesture(OverlayWindowControl::kMute); - event->SetHandled(); } else if (GetSkipAdControlsBounds().Contains(event->location())) { controller_->SkipAd(); RecordTapGesture(OverlayWindowControl::kSkipAd); @@ -984,11 +925,6 @@ RecordButtonPressed(OverlayWindowControl::kBackToTab); } - if (sender == mute_controls_view_) { - ToggleMute(); - RecordButtonPressed(OverlayWindowControl::kMute); - } - if (sender == skip_ad_controls_view_) { controller_->SkipAd(); RecordButtonPressed(OverlayWindowControl::kSkipAd); @@ -1030,10 +966,6 @@ return back_to_tab_controls_view_->GetMirroredBounds(); } -gfx::Rect OverlayWindowViews::GetMuteControlsBounds() { - return mute_controls_view_->GetMirroredBounds(); -} - gfx::Rect OverlayWindowViews::GetSkipAdControlsBounds() { return skip_ad_controls_view_->GetMirroredBounds(); } @@ -1078,10 +1010,6 @@ return back_to_tab_controls_view_->layer(); } -ui::Layer* OverlayWindowViews::GetMuteControlsLayer() { - return mute_controls_view_->layer(); -} - ui::Layer* OverlayWindowViews::GetCloseControlsLayer() { return close_controls_view_->layer(); } @@ -1124,14 +1052,6 @@ play_pause_controls_view_->SetPlaybackState(is_active ? kPlaying : kPaused); } -void OverlayWindowViews::ToggleMute() { - // Retrieve expected active state based on what command was sent in - // ToggleMute() since the IPC message may not have been propagated - // the media player yet. - bool muted = controller_->ToggleMute(); - mute_controls_view_->SetMutedState(muted ? kMuted : kUnmuted); -} - views::PlaybackImageButton* OverlayWindowViews::play_pause_controls_view_for_testing() const { return play_pause_controls_view_; @@ -1160,10 +1080,6 @@ return close_controls_view_->origin(); } -gfx::Point OverlayWindowViews::mute_image_position_for_testing() const { - return mute_controls_view_->origin(); -} - #if defined(OS_CHROMEOS) gfx::Point OverlayWindowViews::resize_handle_position_for_testing() const { return resize_handle_view_->origin(); @@ -1175,11 +1091,6 @@ return playback_state_for_testing_; } -OverlayWindowViews::MutedState OverlayWindowViews::muted_state_for_testing() - const { - return muted_state_for_testing_; -} - ui::Layer* OverlayWindowViews::video_layer_for_testing() const { return video_view_->layer(); }
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h index 84fe557..a34d2197 100644 --- a/chrome/browser/ui/views/overlay/overlay_window_views.h +++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -19,7 +19,6 @@ namespace views { class BackToTabImageButton; class CloseImageButton; -class MuteImageButton; class PlaybackImageButton; class ResizeHandleButton; class SkipAdLabelButton; @@ -49,7 +48,6 @@ void UpdateVideoSize(const gfx::Size& natural_size) override; void SetPlaybackState(PlaybackState playback_state) override; void SetAlwaysHidePlayPauseButton(bool is_visible) override; - void SetMutedState(MutedState muted) override; void SetSkipAdButtonVisibility(bool is_visible) override; void SetNextTrackButtonVisibility(bool is_visible) override; void SetPreviousTrackButtonVisibility(bool is_visible) override; @@ -74,7 +72,6 @@ // Gets the bounds of the controls. gfx::Rect GetBackToTabControlsBounds(); - gfx::Rect GetMuteControlsBounds(); gfx::Rect GetSkipAdControlsBounds(); gfx::Rect GetCloseControlsBounds(); gfx::Rect GetResizeHandleControlsBounds(); @@ -96,10 +93,8 @@ views::SkipAdLabelButton* skip_ad_controls_view_for_testing() const; gfx::Point back_to_tab_image_position_for_testing() const; gfx::Point close_image_position_for_testing() const; - gfx::Point mute_image_position_for_testing() const; gfx::Point resize_handle_position_for_testing() const; OverlayWindowViews::PlaybackState playback_state_for_testing() const; - OverlayWindowViews::MutedState muted_state_for_testing() const; ui::Layer* video_layer_for_testing() const; cc::Layer* GetLayerForTesting() override; @@ -144,7 +139,6 @@ ui::Layer* GetControlsScrimLayer(); ui::Layer* GetBackToTabControlsLayer(); - ui::Layer* GetMuteControlsLayer(); ui::Layer* GetCloseControlsLayer(); ui::Layer* GetResizeHandleLayer(); ui::Layer* GetControlsParentLayer(); @@ -153,7 +147,7 @@ // numeric values should never be reused. enum class OverlayWindowControl { kBackToTab = 0, - kMute, + kMuteDeprecated, kSkipAd, kClose, kPlayPause, @@ -169,11 +163,6 @@ // state. void TogglePlayPause(); - // Toggles the mute control through the |controller_| and updates the - // |mute_controls_view_| toggled state to reflect the current muted - // state. - void ToggleMute(); - // Returns the current frame sink id for the surface displayed in the // |video_view_]. If |video_view_| is not currently displaying a surface then // returns nullptr. @@ -222,7 +211,6 @@ views::TrackImageButton* previous_track_controls_view_ = nullptr; views::PlaybackImageButton* play_pause_controls_view_ = nullptr; views::TrackImageButton* next_track_controls_view_ = nullptr; - views::MuteImageButton* mute_controls_view_ = nullptr; views::SkipAdLabelButton* skip_ad_controls_view_ = nullptr; views::ResizeHandleButton* resize_handle_view_ = nullptr; #if defined(OS_CHROMEOS) @@ -239,14 +227,6 @@ // used to toggle play/pause/replay button. PlaybackState playback_state_for_testing_ = kEndOfVideo; - // Current muted state on the video in Picture-in-Picture window. It is - // used to toggle mute button. - MutedState muted_state_for_testing_ = kNoAudio; - - // Whether or not the mute button will be shown. This is not the case when - // there is no audio track. - bool show_mute_button_ = false; - // Whether or not the skip ad button will be shown. This is the // case when Media Session "skipad" action is handled by the website. bool show_skip_ad_button_ = false;
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc index e71ae5f..832c30d 100644 --- a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc +++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc
@@ -40,10 +40,6 @@ return ClickToCallUiController::GetOrCreateFromWebContents(web_contents); } -base::Optional<int> ClickToCallIconView::GetSuccessMessageId() const { - return IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_SEND_SUCCESS; -} - base::string16 ClickToCallIconView::GetTextForTooltipAndAccessibleName() const { return l10n_util::GetStringUTF16( IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TITLE_LABEL);
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h index 737238a..57736b9 100644 --- a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h +++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h
@@ -29,7 +29,6 @@ // SharingIconView SharingUiController* GetController() const override; - base::Optional<int> GetSuccessMessageId() const override; DISALLOW_COPY_AND_ASSIGN(ClickToCallIconView); };
diff --git a/chrome/browser/ui/views/sharing/sharing_icon_view.cc b/chrome/browser/ui/views/sharing/sharing_icon_view.cc index 54ec002..cc14924 100644 --- a/chrome/browser/ui/views/sharing/sharing_icon_view.cc +++ b/chrome/browser/ui/views/sharing/sharing_icon_view.cc
@@ -5,18 +5,16 @@ #include "chrome/browser/ui/views/sharing/sharing_icon_view.h" #include "chrome/app/vector_icons/vector_icons.h" #include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/scoped_canvas.h" +#include "ui/strings/grit/ui_strings.h" #include "ui/views/animation/ink_drop.h" namespace { -// Height of the loader bar in DIP. -constexpr float kLoaderHeight = 4.0f; -// Width of the loader bar in percent of its range. -constexpr float kLoaderWidth = 0.2f; - // TODO(knollr): move these into IconLabelBubbleView. constexpr int kIconTextSpacing = 8; constexpr int kIconTextSpacingTouch = 10; + +// Progress state when the full length of the animation text is visible. +constexpr double kAnimationTextFullLengthShownProgressState = 0.5; } // namespace SharingIconView::SharingIconView(PageActionIconView::Delegate* delegate) @@ -24,7 +22,6 @@ /*command_id=*/0, delegate) { SetVisible(false); - UpdateLoaderColor(); SetUpForInOutAnimation(); } @@ -33,30 +30,31 @@ void SharingIconView::StartLoadingAnimation() { if (loading_animation_) return; - loading_animation_ = std::make_unique<gfx::ThrobAnimation>(this); - loading_animation_->SetTweenType(gfx::Tween::LINEAR); - loading_animation_->SetThrobDuration(750); - loading_animation_->StartThrobbing(-1); + + loading_animation_ = true; + AnimateIn(IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL); SchedulePaint(); } -void SharingIconView::StopLoadingAnimation(base::Optional<int> string_id) { +void SharingIconView::StopLoadingAnimation() { if (!loading_animation_) return; - if (!should_show_error_) - AnimateIn(string_id); - - loading_animation_.reset(); + loading_animation_ = false; + UnpauseAnimation(); SchedulePaint(); } +// TODO(knollr): Introduce IconState / ControllerState {eg, Hidden, Success, +// Sending} to define the various cases instead of a number of if else +// statements. bool SharingIconView::Update() { auto* controller = GetController(); if (!controller) return false; - if (should_show_error() != controller->send_failed()) { + // To ensure that we reset error icon badge. + if (!GetVisible()) { set_should_show_error(controller->send_failed()); UpdateIconImage(); } @@ -64,17 +62,15 @@ if (controller->is_loading()) StartLoadingAnimation(); else - StopLoadingAnimation(GetSuccessMessageId()); + StopLoadingAnimation(); - const bool is_bubble_showing = IsBubbleShowing(); - - if (is_bubble_showing || IsLoadingAnimationVisible() || - last_controller_ != controller) { + if (last_controller_ != controller) { ResetSlideAnimation(/*show=*/false); } last_controller_ = controller; + const bool is_bubble_showing = IsBubbleShowing(); const bool is_visible = is_bubble_showing || IsLoadingAnimationVisible() || label()->GetVisible(); const bool visibility_changed = GetVisible() != is_visible; @@ -84,50 +80,6 @@ return visibility_changed; } -void SharingIconView::UpdateLoaderColor() { - loader_color_ = GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_ProminentButtonColor); -} - -void SharingIconView::OnThemeChanged() { - PageActionIconView::OnThemeChanged(); - UpdateLoaderColor(); -} - -void SharingIconView::PaintButtonContents(gfx::Canvas* canvas) { - PageActionIconView::PaintButtonContents(canvas); - if (!loading_animation_) - return; - - // TODO(knollr): Add support for this animation to PageActionIconView if other - // features need it as well. - - gfx::ScopedCanvas scoped_canvas(canvas); - const float scale = canvas->UndoDeviceScaleFactor(); - const gfx::Rect icon_bounds = - gfx::ScaleToEnclosedRect(image()->bounds(), scale); - const float progress = loading_animation_->GetCurrentValue(); - const float range = icon_bounds.width(); - const float offset = icon_bounds.x(); - - // Calculate start and end in percent of range. - float start = std::max(0.0f, (progress - kLoaderWidth) / (1 - kLoaderWidth)); - float end = std::min(1.0f, progress / (1 - kLoaderWidth)); - // Convert percentages to actual location. - const float size = kLoaderHeight * scale; - start = start * (range - size); - end = end * (range - size) + size; - - gfx::RectF bounds(start + offset, icon_bounds.bottom() - size, end - start, - size); - - cc::PaintFlags flags; - flags.setAntiAlias(true); - flags.setStyle(cc::PaintFlags::kFill_Style); - flags.setColor(loader_color_); - canvas->DrawRoundRect(bounds, bounds.height() / 2, flags); -} - double SharingIconView::WidthMultiplier() const { double multiplier = PageActionIconView::WidthMultiplier(); @@ -145,16 +97,25 @@ } void SharingIconView::AnimationProgressed(const gfx::Animation* animation) { - if (animation != loading_animation_.get()) { - UpdateOpacity(); - return PageActionIconView::AnimationProgressed(animation); + if (animation->is_animating() && + GetAnimationValue() >= kAnimationTextFullLengthShownProgressState && + loading_animation_) { + PauseAnimation(); } - SchedulePaint(); + UpdateOpacity(); + return PageActionIconView::AnimationProgressed(animation); } void SharingIconView::AnimationEnded(const gfx::Animation* animation) { PageActionIconView::AnimationEnded(animation); UpdateOpacity(); + + auto* controller = GetController(); + if (controller && should_show_error() != controller->send_failed()) { + set_should_show_error(controller->send_failed()); + UpdateIconImage(); + controller->MaybeShowErrorDialog(); + } Update(); } @@ -194,5 +155,5 @@ PageActionIconView::ExecuteSource execute_source) {} bool SharingIconView::IsLoadingAnimationVisible() { - return loading_animation_.get(); + return loading_animation_; }
diff --git a/chrome/browser/ui/views/sharing/sharing_icon_view.h b/chrome/browser/ui/views/sharing/sharing_icon_view.h index d035357d..b3fe88c 100644 --- a/chrome/browser/ui/views/sharing/sharing_icon_view.h +++ b/chrome/browser/ui/views/sharing/sharing_icon_view.h
@@ -9,10 +9,6 @@ #include "chrome/browser/ui/views/page_action/page_action_icon_view.h" #include "third_party/skia/include/core/SkColor.h" -namespace gfx { -class Canvas; -class ThrobAnimation; -} // namespace gfx // The location bar icon to show the sharing features bubble. class SharingIconView : public PageActionIconView { @@ -21,13 +17,7 @@ ~SharingIconView() override; void StartLoadingAnimation(); - void StopLoadingAnimation(base::Optional<int> string_id); - - // views::View: - void OnThemeChanged() override; - - // views::Button: - void PaintButtonContents(gfx::Canvas* canvas) override; + void StopLoadingAnimation(); protected: // PageActionIconView: @@ -43,7 +33,6 @@ void UpdateInkDrop(bool activate); void UpdateOpacity(); - void UpdateLoaderColor(); bool IsLoadingAnimationVisible(); bool should_show_error() { return should_show_error_; } void set_should_show_error(bool should_show_error) { @@ -52,14 +41,11 @@ // Get the supporting controller for this icon view. virtual SharingUiController* GetController() const = 0; - // Return the success delivery message Id. - virtual base::Optional<int> GetSuccessMessageId() const = 0; private: SharingUiController* last_controller_ = nullptr; - std::unique_ptr<gfx::ThrobAnimation> loading_animation_; + bool loading_animation_ = false; bool should_show_error_ = false; - SkColor loader_color_; DISALLOW_COPY_AND_ASSIGN(SharingIconView); };
diff --git a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc index 087d86a..e2de1a9 100644 --- a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/chromeos/set_time_dialog.h" #include "chrome/browser/chromeos/system/timezone_resolver_manager.h" #include "chrome/browser/chromeos/system/timezone_util.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chromeos/constants/chromeos_switches.h" #include "chromeos/dbus/system_clock/system_clock_client.h" @@ -76,6 +77,9 @@ html_source->AddString( "timeZoneID", system::TimezoneSettings::GetInstance()->GetCurrentTimezoneID()); + html_source->AddBoolean( + "timeActionsProtectedForChild", + base::FeatureList::IsEnabled(features::kParentAccessCodeForTimeChange)); return new DateTimeHandler; }
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index 158ff09..61d1e49 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1973,7 +1973,6 @@ IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_LESS_SECURE}, {"lockScreenDeleteFingerprintLabel", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_DELETE_FINGERPRINT_ARIA_LABEL}, - {"lockScreenMediaControls", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_MEDIA_CONTROLS}, {"lockScreenNotificationHide", IDS_ASH_SETTINGS_LOCK_SCREEN_NOTIFICATION_HIDE}, {"lockScreenNotificationHideSensitive",
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc index a2d73594..3ea47f5 100644 --- a/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -487,9 +487,6 @@ html_source->AddBoolean( "lockScreenHideSensitiveNotificationsSupported", ash::features::IsLockScreenHideSensitiveNotificationsSupported()); - html_source->AddBoolean( - "lockScreenMediaControlsEnabled", - base::FeatureList::IsEnabled(ash::features::kLockScreenMediaControls)); html_source->AddBoolean("showTechnologyBadge", !ash::features::IsSeparateNetworkIconsEnabled()); html_source->AddBoolean("hasInternalStylus",
diff --git a/chrome/browser/unexpire_flags.cc b/chrome/browser/unexpire_flags.cc new file mode 100644 index 0000000..d92c873 --- /dev/null +++ b/chrome/browser/unexpire_flags.cc
@@ -0,0 +1,46 @@ +// Copyright 2019 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/unexpire_flags.h" + +#include "chrome/browser/expired_flags_list.h" + +namespace flags { + +const base::Feature kUnexpireFlagsM76{"TemporaryUnexpireFlagsM76", + base::FEATURE_DISABLED_BY_DEFAULT}; + +bool ExpiryEnabledForMstone(int mstone) { + // generate_expired_list.py will never emit flags with expiry milestone -1, to + // keep binary size down. However, if a bug *did* cause that to happen, and + // this function did not handle that case, disaster could ensue: all the -1 + // flags that are supposed to never expire would in fact expire instantly, + // since -1 < x for any valid mstone x. + // As such, there's an extra error-check here: never allow flags with mstone + // -1 to expire. + DCHECK(mstone != -1); + if (mstone == -1) + return false; + + // Currently expiration targets flags expiring in M76 or earlier. In M79 this + // will become M78 or earlier; in M80 it will become M80 or earlier, and in + // all future milestones Mx it will be Mx or earlier, so this logic will cease + // to hardcode a milestone and instead target the current major version. + if (mstone < 76) + return true; + if (mstone == 76) + return !base::FeatureList::IsEnabled(kUnexpireFlagsM76); + return false; +} + +bool IsFlagExpired(const char* internal_name) { + for (int i = 0; kExpiredFlags[i].name; ++i) { + const ExpiredFlag* f = &kExpiredFlags[i]; + if (!strcmp(f->name, internal_name) && ExpiryEnabledForMstone(f->mstone)) + return true; + } + return false; +} + +} // namespace flags
diff --git a/chrome/browser/unexpire_flags.h b/chrome/browser/unexpire_flags.h new file mode 100644 index 0000000..4ee8513 --- /dev/null +++ b/chrome/browser/unexpire_flags.h
@@ -0,0 +1,18 @@ +// Copyright 2019 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_UNEXPIRE_FLAGS_H_ +#define CHROME_BROWSER_UNEXPIRE_FLAGS_H_ + +#include "base/feature_list.h" + +namespace flags { + +extern const base::Feature kUnexpireFlagsM76; + +bool IsFlagExpired(const char* internal_name); + +} // namespace flags + +#endif // CHROME_BROWSER_UNEXPIRE_FLAGS_H_
diff --git a/chrome/common/extensions/api/settings_private.idl b/chrome/common/extensions/api/settings_private.idl index 68c058b..b4a1848d 100644 --- a/chrome/common/extensions/api/settings_private.idl +++ b/chrome/common/extensions/api/settings_private.idl
@@ -23,7 +23,16 @@ CHILD_RESTRICTION }; - enum Enforcement { ENFORCED, RECOMMENDED }; + enum Enforcement { + // Value cannot be changed by user. + ENFORCED, + // Value can be changed, but the administrator recommends a default. + RECOMMENDED, + // Value is protected by a code that only parents can access. The logic to + // require the code is NOT automatically added to a preference using this + // enforcement. This is only used to display the correct pref indicator. + PARENT_SUPERVISED + }; dictionary PrefObject { // The key for the pref.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index d02280c..b2dacade 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3763,7 +3763,6 @@ "../browser/ui/extensions/extension_action_view_controller_unittest.cc", "../browser/ui/extensions/extension_message_bubble_bridge_unittest.cc", "../browser/ui/global_error/global_error_service_unittest.cc", - "../browser/ui/global_media_controls/media_dialog_controller_unittest.cc", "../browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc", "../browser/ui/hid/hid_chooser_controller_unittest.cc", "../browser/ui/in_product_help/active_tab_tracker_unittest.cc", @@ -4575,6 +4574,7 @@ "../browser/safe_browsing/download_protection/binary_upload_service_unittest.cc", "../browser/safe_browsing/download_protection/download_feedback_service_unittest.cc", "../browser/safe_browsing/download_protection/download_feedback_unittest.cc", + "../browser/safe_browsing/download_protection/download_item_request_unittest.cc", "../browser/safe_browsing/download_protection/download_protection_service_unittest.cc", "../browser/safe_browsing/download_protection/file_analyzer_unittest.cc", "../browser/safe_browsing/download_protection/multipart_uploader_unittest.cc",
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc index c96476c..6ec296d 100644 --- a/chrome/test/base/in_process_browser_test.cc +++ b/chrome/test/base/in_process_browser_test.cc
@@ -450,6 +450,12 @@ } #endif // !defined(OS_MACOSX) +void InProcessBrowserTest::SelectFirstBrowser() { + const BrowserList* browser_list = BrowserList::GetInstance(); + if (!browser_list->empty()) + browser_ = browser_list->get(0); +} + void InProcessBrowserTest::AddBlankTabAndShow(Browser* browser) { content::WindowedNotificationObserver observer( content::NOTIFICATION_LOAD_STOP, @@ -498,9 +504,8 @@ // Pump startup related events. content::RunAllPendingInMessageLoop(); - const BrowserList* active_browser_list = BrowserList::GetInstance(); - if (!active_browser_list->empty()) { - browser_ = active_browser_list->get(0); + SelectFirstBrowser(); + if (browser_) { #if defined(OS_CHROMEOS) // There are cases where windows get created maximized by default. if (browser_->window()->IsMaximized())
diff --git a/chrome/test/base/in_process_browser_test.h b/chrome/test/base/in_process_browser_test.h index db51b8d..020d928f 100644 --- a/chrome/test/base/in_process_browser_test.h +++ b/chrome/test/base/in_process_browser_test.h
@@ -147,6 +147,9 @@ } // Returns the browser created by BrowserMain(). + // If no browser is created in BrowserMain(), this will return nullptr unless + // another browser instance is created at a later time and + // SelectFirstBrowser() is called. Browser* browser() const { return browser_; } protected: @@ -223,6 +226,12 @@ // the browser. Browser* CreateBrowserForApp(const std::string& app_name, Profile* profile); + // Set |browser_| to the first browser on the browser list. + // Call this when your test subclass wants to access a non-null browser + // instance through browser() but browser creation is delayed until after + // PreRunTestOnMainThread(). + void SelectFirstBrowser(); + // Called from the various CreateBrowser methods to add a blank tab, wait for // the navigation to complete, and show the browser's window. void AddBlankTabAndShow(Browser* browser); @@ -263,7 +272,10 @@ static SetUpBrowserFunction* global_browser_set_up_function_; - // Browser created in BrowserMain(). + // Usually references the browser created in BrowserMain(). + // If no browser is created in BrowserMain(), then |browser_| will remain + // nullptr unless SelectFirstBrowser() is called after the creation of the + // first browser instance at a later time. Browser* browser_ = nullptr; // Used to run the process until the BrowserProcess signals the test to quit.
diff --git a/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control.png b/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control.png index abb13a8..45f3e44 100644 --- a/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control.png +++ b/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control.png Binary files differ
diff --git a/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control_crop.png b/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control_crop.png index 877f104..8107134 100644 --- a/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control_crop.png +++ b/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control_crop.png Binary files differ
diff --git a/chrome/test/data/media/picture-in-picture/pixel_expected_play_control.png b/chrome/test/data/media/picture-in-picture/pixel_expected_play_control.png index c6e9b757b..45a6e1c4 100644 --- a/chrome/test/data/media/picture-in-picture/pixel_expected_play_control.png +++ b/chrome/test/data/media/picture-in-picture/pixel_expected_play_control.png Binary files differ
diff --git a/chrome/test/data/media/picture-in-picture/pixel_expected_play_control_crop.png b/chrome/test/data/media/picture-in-picture/pixel_expected_play_control_crop.png index a055df07..5bfbcd2d 100644 --- a/chrome/test/data/media/picture-in-picture/pixel_expected_play_control_crop.png +++ b/chrome/test/data/media/picture-in-picture/pixel_expected_play_control_crop.png Binary files differ
diff --git a/chrome/test/data/media/picture-in-picture/window-size.html b/chrome/test/data/media/picture-in-picture/window-size.html index d795263..5e82c24 100644 --- a/chrome/test/data/media/picture-in-picture/window-size.html +++ b/chrome/test/data/media/picture-in-picture/window-size.html
@@ -123,12 +123,6 @@ navigator.mediaSession.setActionHandler(name, null); } - function addVolumeChangeEventListener() { - video.addEventListener('volumechange', () => { - document.title = 'muted: ' + video.muted; - }); - } - function addPictureInPictureEventListeners() { video.addEventListener('enterpictureinpicture', () => { document.title = 'enterpictureinpicture';
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js index f2b9377..1c3bc7b4 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
@@ -94,7 +94,8 @@ ]), }; -TEST_F('CrElementsCheckboxTest', 'All', function() { +// crbug.com/997943. +TEST_F('CrElementsCheckboxTest', 'DISABLED_All', function() { mocha.run(); });
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js index e257c4c..f440d45 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js
@@ -60,6 +60,6 @@ } }; -TEST_F('CrElementsInputV3Test', 'All', function() { +TEST_F('CrElementsInputV3Test', 'DISABLED_All', function() { mocha.run(); });
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js index 7bbdc96..b6af9ca 100644 --- a/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js +++ b/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js
@@ -58,5 +58,13 @@ indicator.set('pref.value', 'bar'); Polymer.dom.flush(); assertEquals('matches', icon.tooltipText); + + indicator.set( + 'pref.enforcement', + chrome.settingsPrivate.Enforcement.PARENT_SUPERVISED); + Polymer.dom.flush(); + assertFalse(icon.hidden); + assertEquals('cr20:kite', icon.iconClass); + assertEquals(CrPolicyStrings.controlledSettingParent, icon.tooltipText); }); });
diff --git a/chrome/test/data/webui/cr_elements/settings_private_test_constants.js b/chrome/test/data/webui/cr_elements/settings_private_test_constants.js index cb281b1..00789b54 100644 --- a/chrome/test/data/webui/cr_elements/settings_private_test_constants.js +++ b/chrome/test/data/webui/cr_elements/settings_private_test_constants.js
@@ -20,6 +20,7 @@ chrome.settingsPrivate.Enforcement = { ENFORCED: 'ENFORCED', RECOMMENDED: 'RECOMMENDED', + PARENT_SUPERVISED: 'PARENT_SUPERVISED', }; /** @enum {string} */
diff --git a/chrome/test/data/webui/settings/chromeos/quick_unlock_authenticate_browsertest_chromeos.js b/chrome/test/data/webui/settings/chromeos/quick_unlock_authenticate_browsertest_chromeos.js index dc75ad8..5b71068 100644 --- a/chrome/test/data/webui/settings/chromeos/quick_unlock_authenticate_browsertest_chromeos.js +++ b/chrome/test/data/webui/settings/chromeos/quick_unlock_authenticate_browsertest_chromeos.js
@@ -272,11 +272,6 @@ key: 'ash.message_center.lock_screen_mode', type: chrome.settingsPrivate.PrefType.STRING, value: 'hide' - }, - { - key: 'ash.lock_screen_media_controls_enabled', - type: chrome.settingsPrivate.PrefType.BOOLEAN, - value: true } ]; fakeSettings = new settings.FakeSettingsPrivate(fakePrefs);
diff --git a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java index b4d01d8..25ac84b 100644 --- a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java +++ b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
@@ -137,6 +137,9 @@ // Additional padding for minimum buffer time, determined experimentally. private static final long MIN_BUFFERED_TIME_PADDING_USEC = 120000; + // Max retries for AudioTrackBuilder + private static final int MAX_RETRIES_FOR_AUDIO_TRACKS = 1; + private static AudioManager sAudioManager; private static int sSessionIdMedia = AudioManager.ERROR; @@ -344,20 +347,24 @@ + " with session-id=" + sessionId); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - AudioTrack.Builder builder = new AudioTrack.Builder(); - builder.setBufferSizeInBytes(bufferSizeInBytes) - .setTransferMode(AUDIO_MODE) - .setAudioAttributes(new AudioAttributes.Builder() - .setUsage(usageType) - .setContentType(contentType) - .build()) - .setAudioFormat(new AudioFormat.Builder() - .setEncoding(AUDIO_FORMAT) - .setSampleRate(mSampleRateInHz) - .setChannelMask(CHANNEL_CONFIG) - .build()); - if (sessionId != AudioManager.ERROR) builder.setSessionId(sessionId); - mAudioTrack = builder.build(); + // Retry if AudioTrack creation fails. + int retries = 0; + do { + AudioTrack.Builder builder = new AudioTrack.Builder(); + builder.setBufferSizeInBytes(bufferSizeInBytes) + .setTransferMode(AUDIO_MODE) + .setAudioAttributes(new AudioAttributes.Builder() + .setUsage(usageType) + .setContentType(contentType) + .build()) + .setAudioFormat(new AudioFormat.Builder() + .setEncoding(AUDIO_FORMAT) + .setSampleRate(mSampleRateInHz) + .setChannelMask(CHANNEL_CONFIG) + .build()); + if (sessionId != AudioManager.ERROR) builder.setSessionId(sessionId); + mAudioTrack = builder.build(); + } while (mAudioTrack == null && retries++ < MAX_RETRIES_FOR_AUDIO_TRACKS); } else { // Using pre-M API. if (sessionId == AudioManager.ERROR) {
diff --git a/chromeos/dbus/fake_cicerone_client.cc b/chromeos/dbus/fake_cicerone_client.cc index 83ea391..45fe2f7 100644 --- a/chromeos/dbus/fake_cicerone_client.cc +++ b/chromeos/dbus/fake_cicerone_client.cc
@@ -192,6 +192,8 @@ const vm_tools::cicerone::StartLxdContainerRequest& request, DBusMethodCallback<vm_tools::cicerone::StartLxdContainerResponse> callback) { + start_lxd_container_response_.mutable_os_release()->CopyFrom( + lxd_container_os_release_); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), start_lxd_container_response_)); @@ -202,6 +204,7 @@ signal.set_vm_name(request.vm_name()); signal.set_container_name(request.container_name()); signal.set_status(lxd_container_starting_signal_status_); + signal.mutable_os_release()->CopyFrom(lxd_container_os_release_); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&FakeCiceroneClient::NotifyLxdContainerStarting,
diff --git a/chromeos/dbus/fake_cicerone_client.h b/chromeos/dbus/fake_cicerone_client.h index 693ee0ef..23729c4f8 100644 --- a/chromeos/dbus/fake_cicerone_client.h +++ b/chromeos/dbus/fake_cicerone_client.h
@@ -342,6 +342,10 @@ std::move(cancel_import_lxd_container_response); } + void set_lxd_container_os_release(vm_tools::cicerone::OsRelease os_release) { + lxd_container_os_release_ = std::move(os_release); + } + // Additional functions to allow tests to trigger Signals. void NotifyLxdContainerCreated( const vm_tools::cicerone::LxdContainerCreatedSignal& signal); @@ -418,6 +422,8 @@ vm_tools::cicerone::CancelImportLxdContainerResponse cancel_import_lxd_container_response_; + vm_tools::cicerone::OsRelease lxd_container_os_release_; + UninstallPackageOwningFileCallback uninstall_package_owning_file_callback_; base::ObserverList<Observer>::Unchecked observer_list_;
diff --git a/components/BUILD.gn b/components/BUILD.gn index 33773d1..2c3a0cae 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -558,7 +558,7 @@ if (is_android) { sources += [ - "autofill_assistant/browser/web_controller_browsertest.cc", + "autofill_assistant/browser/web/web_controller_browsertest.cc", "test/android/browsertests_apk/components_browser_tests_jni_onload.cc", ] sources -= [ "autofill/content/browser/risk/fingerprint_browsertest.cc" ]
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index 6a2ccc63..44b0525 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -162,8 +162,6 @@ "metrics/form_event_logger_base.h", "metrics/form_events.h", "payments/account_info_getter.h", - "payments/autofill_wallet_data_type_controller.cc", - "payments/autofill_wallet_data_type_controller.h", "payments/autofill_wallet_model_type_controller.cc", "payments/autofill_wallet_model_type_controller.h", "payments/card_unmask_delegate.cc", @@ -264,8 +262,6 @@ "webdata/autofill_table_encryptor_factory.h", "webdata/autofill_wallet_metadata_sync_bridge.cc", "webdata/autofill_wallet_metadata_sync_bridge.h", - "webdata/autofill_wallet_metadata_syncable_service.cc", - "webdata/autofill_wallet_metadata_syncable_service.h", "webdata/autofill_wallet_sync_bridge.cc", "webdata/autofill_wallet_sync_bridge.h", "webdata/autofill_webdata_backend.h", @@ -572,7 +568,6 @@ "logging/log_buffer_unittest.cc", "logging/log_manager_unittest.cc", "logging/log_router_unittest.cc", - "payments/autofill_wallet_data_type_controller_unittest.cc", "payments/credit_card_access_manager_unittest.cc", "payments/credit_card_cvc_authenticator_unittest.cc", "payments/credit_card_save_manager_unittest.cc", @@ -600,7 +595,6 @@ "webdata/autofill_sync_bridge_util_unittest.cc", "webdata/autofill_table_unittest.cc", "webdata/autofill_wallet_metadata_sync_bridge_unittest.cc", - "webdata/autofill_wallet_metadata_syncable_service_unittest.cc", "webdata/autofill_wallet_sync_bridge_unittest.cc", "webdata/web_data_service_unittest.cc", ]
diff --git a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc deleted file mode 100644 index e10ace0..0000000 --- a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc +++ /dev/null
@@ -1,105 +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. - -#include "components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h" - -#include <utility> - -#include "base/bind.h" -#include "components/autofill/core/browser/personal_data_manager.h" -#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" -#include "components/autofill/core/common/autofill_prefs.h" -#include "components/prefs/pref_service.h" -#include "components/sync/base/data_type_histogram.h" -#include "components/sync/driver/sync_client.h" -#include "components/sync/driver/sync_service.h" -#include "components/sync/model/sync_error.h" -#include "components/sync/model/syncable_service.h" - -namespace browser_sync { - -AutofillWalletDataTypeController::AutofillWalletDataTypeController( - syncer::ModelType type, - scoped_refptr<base::SequencedTaskRunner> db_thread, - const base::RepeatingClosure& dump_stack, - syncer::SyncService* sync_service, - syncer::SyncClient* sync_client, - const PersonalDataManagerProvider& pdm_provider, - const scoped_refptr<autofill::AutofillWebDataService>& web_data_service) - : AsyncDirectoryTypeController(type, - dump_stack, - sync_service, - sync_client, - syncer::GROUP_DB, - std::move(db_thread)), - pdm_provider_(pdm_provider), - callback_registered_(false), - web_data_service_(web_data_service), - currently_enabled_(IsEnabled()) { - DCHECK(type == syncer::AUTOFILL_WALLET_METADATA); - pref_registrar_.Init(sync_client->GetPrefService()); - pref_registrar_.Add( - autofill::prefs::kAutofillWalletImportEnabled, - base::BindRepeating(&AutofillWalletDataTypeController::OnUserPrefChanged, - base::Unretained(this))); - pref_registrar_.Add( - autofill::prefs::kAutofillCreditCardEnabled, - base::BindRepeating(&AutofillWalletDataTypeController::OnUserPrefChanged, - base::AsWeakPtr(this))); -} - -AutofillWalletDataTypeController::~AutofillWalletDataTypeController() {} - -bool AutofillWalletDataTypeController::StartModels() { - DCHECK(CalledOnValidThread()); - DCHECK_EQ(state(), MODEL_STARTING); - - if (!IsEnabled()) - return false; - - if (!web_data_service_) - return false; - - if (web_data_service_->IsDatabaseLoaded()) - return true; - - if (!callback_registered_) { - web_data_service_->RegisterDBLoadedCallback( - base::BindRepeating(&AutofillWalletDataTypeController::OnModelLoaded, - base::AsWeakPtr(this))); - callback_registered_ = true; - } - - return false; -} - -syncer::DataTypeController::PreconditionState -AutofillWalletDataTypeController::GetPreconditionState() const { - DCHECK(CalledOnValidThread()); - return currently_enabled_ ? PreconditionState::kPreconditionsMet - : PreconditionState::kMustStopAndClearData; -} - -void AutofillWalletDataTypeController::OnUserPrefChanged() { - DCHECK(CalledOnValidThread()); - - bool new_enabled = IsEnabled(); - if (currently_enabled_ == new_enabled) - return; // No change to sync state. - currently_enabled_ = new_enabled; - - sync_service()->DataTypePreconditionChanged(type()); -} - -bool AutofillWalletDataTypeController::IsEnabled() { - DCHECK(CalledOnValidThread()); - - // Require the user-visible pref to be enabled to sync Wallet data/metadata. - return sync_client()->GetPrefService()->GetBoolean( - autofill::prefs::kAutofillWalletImportEnabled) && - sync_client()->GetPrefService()->GetBoolean( - autofill::prefs::kAutofillCreditCardEnabled); -} - -} // namespace browser_sync
diff --git a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h deleted file mode 100644 index aab8cc2..0000000 --- a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h +++ /dev/null
@@ -1,77 +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. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_ - -#include "base/callback.h" -#include "base/macros.h" -#include "base/sequenced_task_runner.h" -#include "components/prefs/pref_change_registrar.h" -#include "components/sync/driver/async_directory_type_controller.h" - -namespace autofill { -class AutofillWebDataService; -class PersonalDataManager; -} // namespace autofill - -namespace syncer { -class SyncClient; -class SyncService; -} // namespace syncer - -namespace browser_sync { - -// Controls syncing of AUTOFILL_WALLET_METADATA. -class AutofillWalletDataTypeController - : public syncer::AsyncDirectoryTypeController { - public: - using PersonalDataManagerProvider = - base::RepeatingCallback<autofill::PersonalDataManager*()>; - - // |type| should be AUTOFILL_WALLET_METADATA. - // |dump_stack| is called when an unrecoverable error occurs. - AutofillWalletDataTypeController( - syncer::ModelType type, - scoped_refptr<base::SequencedTaskRunner> db_thread, - const base::RepeatingClosure& dump_stack, - syncer::SyncService* sync_service, - syncer::SyncClient* sync_client, - const PersonalDataManagerProvider& pdm_provider, - const scoped_refptr<autofill::AutofillWebDataService>& web_data_service); - ~AutofillWalletDataTypeController() override; - - // AsyncDirectoryTypeController implementation. - bool StartModels() override; - PreconditionState GetPreconditionState() const override; - - private: - // Callback for changes to the autofill pref. - void OnUserPrefChanged(); - - // Returns true if the prefs are set such that wallet sync should be enabled. - bool IsEnabled(); - - // Callback that allows accessing PersonalDataManager lazily. - const PersonalDataManagerProvider pdm_provider_; - - // Whether the database loaded callback has been registered. - bool callback_registered_; - - // A reference to the AutofillWebDataService for this controller. - scoped_refptr<autofill::AutofillWebDataService> web_data_service_; - - // Stores whether we're currently syncing wallet data. This is the last - // value computed by IsEnabled. - bool currently_enabled_; - - // Registrar for listening to kAutofillWalletSyncExperimentEnabled status. - PrefChangeRegistrar pref_registrar_; - - DISALLOW_COPY_AND_ASSIGN(AutofillWalletDataTypeController); -}; - -} // namespace browser_sync - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
diff --git a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc deleted file mode 100644 index 4586d28..0000000 --- a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc +++ /dev/null
@@ -1,257 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h" - -#include <memory> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/test/task_environment.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" -#include "components/autofill/core/common/autofill_prefs.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/pref_service.h" -#include "components/prefs/testing_pref_service.h" -#include "components/sync/driver/configure_context.h" -#include "components/sync/driver/data_type_controller_mock.h" -#include "components/sync/driver/fake_generic_change_processor.h" -#include "components/sync/driver/mock_sync_service.h" -#include "components/sync/driver/sync_client_mock.h" -#include "components/sync/driver/sync_service.h" -#include "components/sync/model/fake_syncable_service.h" -#include "components/sync/model/sync_error.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace browser_sync { - -namespace { - -using autofill::AutofillWebDataService; -using testing::_; -using testing::Return; - -// Fake WebDataService implementation that stubs out the database loading. -class FakeWebDataService : public AutofillWebDataService { - public: - FakeWebDataService( - const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner, - const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner) - : AutofillWebDataService(ui_task_runner, db_task_runner), - is_database_loaded_(false), - db_loaded_callback_(base::RepeatingCallback<void(void)>()) {} - - // Mark the database as loaded and send out the appropriate notification. - void LoadDatabase() { - is_database_loaded_ = true; - - if (!db_loaded_callback_.is_null()) { - db_loaded_callback_.Run(); - // Clear the callback here or the WDS and DTC will have refs to each other - // and create a memory leak. - // TODO(crbug.com/941530): Solve this with a OnceCallback. Note that - // RegisterDBLoadedCallback overrides other functions that still use - // base::[Repeating]Callbacks, so it would affect non-Autofill code. - db_loaded_callback_ = base::RepeatingCallback<void(void)>(); - } - } - - bool IsDatabaseLoaded() override { return is_database_loaded_; } - - void RegisterDBLoadedCallback( - const base::RepeatingCallback<void(void)>& callback) override { - db_loaded_callback_ = callback; - } - - private: - ~FakeWebDataService() override {} - - bool is_database_loaded_; - base::RepeatingCallback<void(void)> db_loaded_callback_; - - DISALLOW_COPY_AND_ASSIGN(FakeWebDataService); -}; - -class AutofillWalletDataTypeControllerTest : public testing::Test { - public: - AutofillWalletDataTypeControllerTest() : last_type_(syncer::UNSPECIFIED) { - ON_CALL(sync_service_, GetUserShare()).WillByDefault(Return(&user_share_)); - } - - ~AutofillWalletDataTypeControllerTest() override {} - - void SetUp() override { - prefs_.registry()->RegisterBooleanPref( - autofill::prefs::kAutofillWalletImportEnabled, true); - prefs_.registry()->RegisterBooleanPref( - autofill::prefs::kAutofillCreditCardEnabled, true); - - ON_CALL(sync_client_, GetPrefService()).WillByDefault(Return(&prefs_)); - ON_CALL(sync_client_, GetSyncableServiceForType(_)) - .WillByDefault(Return(syncable_service_.AsWeakPtr())); - - web_data_service_ = base::MakeRefCounted<FakeWebDataService>( - base::ThreadTaskRunnerHandle::Get(), - base::ThreadTaskRunnerHandle::Get()); - autofill_wallet_dtc_ = std::make_unique<AutofillWalletDataTypeController>( - syncer::AUTOFILL_WALLET_METADATA, base::ThreadTaskRunnerHandle::Get(), - /*dump_stack=*/base::DoNothing(), &sync_service_, &sync_client_, - AutofillWalletDataTypeController::PersonalDataManagerProvider(), - web_data_service_); - - last_type_ = syncer::UNSPECIFIED; - last_error_ = syncer::SyncError(); - } - - void TearDown() override { - // Make sure WebDataService is shutdown properly on DB thread before we - // destroy it. - // Must be done before we pump the loop. - syncable_service_.StopSyncing(syncer::AUTOFILL_WALLET_METADATA); - } - - protected: - void SetStartExpectations() { - autofill_wallet_dtc_->SetGenericChangeProcessorFactoryForTest( - std::make_unique<syncer::FakeGenericChangeProcessorFactory>( - std::make_unique<syncer::FakeGenericChangeProcessor>( - syncer::AUTOFILL_WALLET_METADATA))); - } - - bool Start() { - autofill_wallet_dtc_->LoadModels( - syncer::ConfigureContext(), - base::BindRepeating( - &AutofillWalletDataTypeControllerTest::OnLoadFinished, - base::Unretained(this))); - base::RunLoop().RunUntilIdle(); - if (autofill_wallet_dtc_->state() != - syncer::DataTypeController::MODEL_LOADED) { - return false; - } - autofill_wallet_dtc_->StartAssociating(base::BindRepeating( - &syncer::StartCallbackMock::Run, base::Unretained(&start_callback_))); - base::RunLoop().RunUntilIdle(); - return true; - } - - void OnLoadFinished(syncer::ModelType type, const syncer::SyncError& error) { - last_type_ = type; - last_error_ = error; - } - - base::test::TaskEnvironment task_environment_; - TestingPrefServiceSimple prefs_; - syncer::UserShare user_share_; - testing::NiceMock<syncer::MockSyncService> sync_service_; - syncer::StartCallbackMock start_callback_; - syncer::FakeSyncableService syncable_service_; - std::unique_ptr<AutofillWalletDataTypeController> autofill_wallet_dtc_; - scoped_refptr<FakeWebDataService> web_data_service_; - testing::NiceMock<syncer::SyncClientMock> sync_client_; - - syncer::ModelType last_type_; - syncer::SyncError last_error_; -}; - -TEST_F(AutofillWalletDataTypeControllerTest, StartDatatypeEnabled) { - SetStartExpectations(); - web_data_service_->LoadDatabase(); - EXPECT_CALL(start_callback_, - Run(syncer::DataTypeController::OK, testing::_, testing::_)); - - EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING, - autofill_wallet_dtc_->state()); - Start(); - EXPECT_FALSE(last_error_.IsSet()); - EXPECT_EQ(syncer::AUTOFILL_WALLET_METADATA, last_type_); - EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state()); -} - -TEST_F(AutofillWalletDataTypeControllerTest, - DatatypeDisabledByWalletImportWhileRunning) { - SetStartExpectations(); - web_data_service_->LoadDatabase(); - EXPECT_CALL(start_callback_, - Run(syncer::DataTypeController::OK, testing::_, testing::_)); - - EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING, - autofill_wallet_dtc_->state()); - Start(); - EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state()); - EXPECT_FALSE(last_error_.IsSet()); - EXPECT_EQ(syncer::AUTOFILL_WALLET_METADATA, last_type_); - - EXPECT_CALL(sync_service_, - DataTypePreconditionChanged(syncer::AUTOFILL_WALLET_METADATA)); - autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, false); - autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, true); - EXPECT_EQ( - syncer::DataTypeController::PreconditionState::kMustStopAndClearData, - autofill_wallet_dtc_->GetPreconditionState()); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(AutofillWalletDataTypeControllerTest, - DatatypeDisabledByCreditCardsWhileRunning) { - SetStartExpectations(); - web_data_service_->LoadDatabase(); - EXPECT_CALL(start_callback_, - Run(syncer::DataTypeController::OK, testing::_, testing::_)); - - EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING, - autofill_wallet_dtc_->state()); - Start(); - EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state()); - EXPECT_FALSE(last_error_.IsSet()); - EXPECT_EQ(syncer::AUTOFILL_WALLET_METADATA, last_type_); - - EXPECT_CALL(sync_service_, - DataTypePreconditionChanged(syncer::AUTOFILL_WALLET_METADATA)); - autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, true); - autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, false); - EXPECT_EQ( - syncer::DataTypeController::PreconditionState::kMustStopAndClearData, - autofill_wallet_dtc_->GetPreconditionState()); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(AutofillWalletDataTypeControllerTest, - DatatypeDisabledByWalletImportAtStartup) { - SetStartExpectations(); - web_data_service_->LoadDatabase(); - autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, false); - autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, true); - EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING, - autofill_wallet_dtc_->state()); - Start(); - base::RunLoop().RunUntilIdle(); - // OnLoadFinished() should not have been called. - EXPECT_EQ(syncer::UNSPECIFIED, last_type_); -} - -TEST_F(AutofillWalletDataTypeControllerTest, - DatatypeDisabledByCreditCardsAtStartup) { - SetStartExpectations(); - web_data_service_->LoadDatabase(); - autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, true); - autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, false); - EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING, - autofill_wallet_dtc_->state()); - Start(); - base::RunLoop().RunUntilIdle(); - // OnLoadFinished() should not have been called. - EXPECT_EQ(syncer::UNSPECIFIED, last_type_); -} - -} // namespace - -} // namespace browser_sync
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc deleted file mode 100644 index 2d97e51..0000000 --- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc +++ /dev/null
@@ -1,808 +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. - -#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h" - -#include <stddef.h> - -#include <utility> -#include <vector> - -#include "base/base64.h" -#include "base/bind.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/numerics/safe_conversions.h" -#include "base/time/time.h" -#include "components/autofill/core/browser/data_model/autofill_data_model.h" -#include "components/autofill/core/browser/data_model/autofill_profile.h" -#include "components/autofill/core/browser/data_model/credit_card.h" -#include "components/autofill/core/browser/webdata/autofill_change.h" -#include "components/autofill/core/browser/webdata/autofill_table.h" -#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" -#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" -#include "components/autofill/core/common/autofill_clock.h" -#include "components/autofill/core/common/autofill_util.h" -#include "components/sync/model/sync_change.h" -#include "components/sync/model/sync_change_processor.h" -#include "components/sync/model/sync_data.h" -#include "components/sync/model/sync_error_factory.h" -#include "components/sync/protocol/sync.pb.h" - -namespace autofill { - -namespace { - -void* AutofillWalletMetadataSyncableServiceUserDataKey() { - // Use the address of a static so that COMDAT folding won't ever fold - // with something else. - static int user_data_key = 0; - return reinterpret_cast<void*>(&user_data_key); -} - -// Sets the common syncable |metadata| for the |local_data_model|. -void SetCommonMetadata(sync_pb::WalletMetadataSpecifics::Type type, - const std::string& server_id, - const AutofillDataModel& local_data_model, - sync_pb::WalletMetadataSpecifics* metadata) { - metadata->set_type(type); - metadata->set_id(server_id); - metadata->set_use_count(local_data_model.use_count()); - metadata->set_use_date(local_data_model.use_date().ToInternalValue()); -} - -// Returns syncable metadata for the |local_profile|. -syncer::SyncData BuildSyncData(sync_pb::WalletMetadataSpecifics::Type type, - const std::string& server_id, - const AutofillProfile& local_profile) { - sync_pb::EntitySpecifics entity; - sync_pb::WalletMetadataSpecifics* metadata = entity.mutable_wallet_metadata(); - SetCommonMetadata(type, server_id, local_profile, metadata); - metadata->set_address_has_converted(local_profile.has_converted()); - std::string sync_tag = "address-" + server_id; - - return syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity); -} - -// Returns syncable metadata for the |local_card|. -syncer::SyncData BuildSyncData(sync_pb::WalletMetadataSpecifics::Type type, - const std::string& server_id, - const CreditCard& local_card) { - sync_pb::EntitySpecifics entity; - sync_pb::WalletMetadataSpecifics* metadata = entity.mutable_wallet_metadata(); - SetCommonMetadata(type, server_id, local_card, metadata); - // The strings must be in valid UTF-8 to sync. - std::string billing_address_id; - base::Base64Encode(local_card.billing_address_id(), &billing_address_id); - metadata->set_card_billing_address_id(billing_address_id); - std::string sync_tag = "card-" + server_id; - - return syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity); -} - -// If the metadata exists locally, undelete it on the sync server. -template <class DataType> -void UndeleteMetadataIfExisting( - const std::string& server_id, - const sync_pb::WalletMetadataSpecifics::Type& metadata_type, - std::unordered_map<std::string, std::unique_ptr<DataType>>* locals, - syncer::SyncChangeList* changes_to_sync) { - const auto& it = locals->find(server_id); - if (it != locals->end()) { - std::unique_ptr<DataType> local_metadata = std::move(it->second); - locals->erase(it); - changes_to_sync->push_back(syncer::SyncChange( - FROM_HERE, syncer::SyncChange::ACTION_ADD, - BuildSyncData(metadata_type, server_id, *local_metadata))); - } -} - -syncer::SyncDataList::iterator FindServerIdAndTypeInCache( - const std::string& server_id, - const sync_pb::WalletMetadataSpecifics::Type& type, - syncer::SyncDataList* cache) { - for (auto it = cache->begin(); it != cache->end(); ++it) { - if (server_id == it->GetSpecifics().wallet_metadata().id() && - type == it->GetSpecifics().wallet_metadata().type()) { - return it; - } - } - - return cache->end(); -} - -syncer::SyncDataList::iterator FindItemInCache(const syncer::SyncData& item, - syncer::SyncDataList* cache) { - return FindServerIdAndTypeInCache( - item.GetSpecifics().wallet_metadata().id(), - item.GetSpecifics().wallet_metadata().type(), cache); -} - -void RemoveItemFromCache(const syncer::SyncData& item, - syncer::SyncDataList* cache) { - auto it = FindItemInCache(item, cache); - if (it != cache->end()) - cache->erase(it); -} - -void AddOrUpdateItemInCache(const syncer::SyncData& item, - syncer::SyncDataList* cache) { - auto it = FindItemInCache(item, cache); - if (it != cache->end()) - *it = item; - else - cache->push_back(item); -} - -void ApplyChangesToCache(const syncer::SyncChangeList& changes, - syncer::SyncDataList* cache) { - for (const syncer::SyncChange& change : changes) { - switch (change.change_type()) { - case syncer::SyncChange::ACTION_ADD: - // Intentional fall through. - case syncer::SyncChange::ACTION_UPDATE: - AddOrUpdateItemInCache(change.sync_data(), cache); - break; - - case syncer::SyncChange::ACTION_DELETE: - RemoveItemFromCache(change.sync_data(), cache); - break; - - case syncer::SyncChange::ACTION_INVALID: - NOTREACHED(); - break; - } - } -} - -template <class DataType> -bool AreLocalUseStatsUpdated(const sync_pb::WalletMetadataSpecifics& remote, - const DataType& local) { - return base::checked_cast<size_t>(remote.use_count()) < local.use_count() && - base::Time::FromInternalValue(remote.use_date()) < local.use_date(); -} - -bool IsLocalBillingAddressUpdated( - const sync_pb::WalletMetadataSpecifics& remote, - const CreditCard& local) { - std::string remote_billing_address_id; - base::Base64Decode(remote.card_billing_address_id(), - &remote_billing_address_id); - return local.billing_address_id() != remote_billing_address_id; -} - -bool IsLocalHasConvertedStatusUpdated( - const sync_pb::WalletMetadataSpecifics& remote, - const AutofillProfile& local) { - return remote.address_has_converted() != local.has_converted(); -} - -// Merges the metadata of the remote and local versions of the data model. -void MergeCommonMetadata( - const sync_pb::WalletMetadataSpecifics& remote_metadata, - AutofillDataModel* local_model, - bool* is_remote_outdated, - bool* is_local_modified) { - size_t remote_use_count = - base::checked_cast<size_t>(remote_metadata.use_count()); - base::Time remote_use_date = - base::Time::FromInternalValue(remote_metadata.use_date()); - - // If the two models have the same metadata, do nothing. - if (local_model->use_count() == remote_use_count && - local_model->use_date() == remote_use_date) { - return; - } - - // Special case for local models with a use_count of one. This means the local - // model was only created, never used. The remote model should always be - // preferred. - // This situation can happen for new Chromium instances where there is no data - // yet on disk, making the use_date artifically high. Once the metadata sync - // kicks in, we should use that value. - if (local_model->use_count() == 1) { - local_model->set_use_date(remote_use_date); - local_model->set_use_count(remote_use_count); - *is_local_modified = true; - } else { - // Otherwise, just keep the most recent use date and biggest use count. - if (local_model->use_date() < remote_use_date) { - local_model->set_use_date(remote_use_date); - *is_local_modified = true; - } else if (local_model->use_date() > remote_use_date) { - *is_remote_outdated = true; - } - - if (local_model->use_count() < remote_use_count) { - local_model->set_use_count(remote_use_count); - *is_local_modified = true; - } else if (local_model->use_count() > remote_use_count) { - *is_remote_outdated = true; - } - } -} - -// Merges the metadata of the remote and local versions of the profile. -void MergeMetadata(const sync_pb::WalletMetadataSpecifics& remote_metadata, - AutofillProfile* local_profile, - bool* is_remote_outdated, - bool* is_local_modified) { - // Merge the has_converted status. - if (local_profile->has_converted() != - remote_metadata.address_has_converted()) { - if (!local_profile->has_converted()) { - local_profile->set_has_converted(true); - *is_local_modified = true; - } else { - *is_remote_outdated = true; - } - } - - // Merge the use_count and use_date. - MergeCommonMetadata(remote_metadata, local_profile, is_remote_outdated, - is_local_modified); -} - -// Whether the |current_billing_address_id| is considered outdated compared to -// the |proposed_billing_address_id|. -bool IsBillingAddressOutdated(const std::string& current_billing_address_id, - const std::string& proposed_billing_address_id) { - DCHECK(current_billing_address_id != proposed_billing_address_id); - - // If the current billing address is empty, or if the current one refers to a - // server address and the proposed one refers to a local address, the current - // billing address is considered outdated. - return current_billing_address_id.empty() || - (current_billing_address_id.size() != kLocalGuidSize && - proposed_billing_address_id.size() == kLocalGuidSize); -} - -// Merges the metadata of the remote and local versions of the credit card. -void MergeMetadata(const sync_pb::WalletMetadataSpecifics& remote_metadata, - CreditCard* local_card, - bool* is_remote_outdated, - bool* is_local_modified) { - // Merge the billing_address_id. Do this before updating the use_count - // because it may be used to determine what id to keep. - std::string remote_billing_address_id; - base::Base64Decode(remote_metadata.card_billing_address_id(), - &remote_billing_address_id); - - if (local_card->billing_address_id() != remote_billing_address_id) { - if (IsBillingAddressOutdated(local_card->billing_address_id(), - remote_billing_address_id)) { - local_card->set_billing_address_id(remote_billing_address_id); - *is_local_modified = true; - } else if (IsBillingAddressOutdated(remote_billing_address_id, - local_card->billing_address_id())) { - *is_remote_outdated = true; - } else { - // The cards have a different non-empty billing address id and both refer - // to the same type of address. Keep the billing address id of the most - // recently used card. If both have the same timestamp, the remote version - // should be kept in order to stabilize the values. - base::Time remote_use_date = - base::Time::FromInternalValue(remote_metadata.use_date()); - if (local_card->use_date() <= remote_use_date) { - local_card->set_billing_address_id(remote_billing_address_id); - *is_local_modified = true; - } else { - *is_remote_outdated = true; - } - } - } - - // Merge the use_count and use_date. - MergeCommonMetadata(remote_metadata, local_card, is_remote_outdated, - is_local_modified); -} - -// Merges |remote| metadata into a collection of metadata |locals|. Returns true -// if the corresponding local metadata was found. -// -// Stores an "update" in |changes_to_sync| if |remote| corresponds to an item in -// |locals| that has higher use count and later use date. -template <class DataType> -bool MergeRemote( - const syncer::SyncData& remote, - const base::Callback<bool(const DataType&)>& updater, - bool* is_any_local_modified, - std::unordered_map<std::string, std::unique_ptr<DataType>>* locals, - syncer::SyncChangeList* changes_to_sync) { - DCHECK(locals); - DCHECK(changes_to_sync); - - const sync_pb::WalletMetadataSpecifics& remote_metadata = - remote.GetSpecifics().wallet_metadata(); - auto it = locals->find(remote_metadata.id()); - if (it == locals->end()) - return false; - - std::unique_ptr<DataType> local_metadata = std::move(it->second); - locals->erase(it); - - bool is_local_modified = false; - bool is_remote_outdated = false; - MergeMetadata(remote_metadata, local_metadata.get(), &is_remote_outdated, - &is_local_modified); - - if (is_remote_outdated) { - changes_to_sync->push_back(syncer::SyncChange( - FROM_HERE, syncer::SyncChange::ACTION_UPDATE, - BuildSyncData(remote_metadata.type(), remote_metadata.id(), - *local_metadata))); - } - - if (is_local_modified) { - updater.Run(*local_metadata); - *is_any_local_modified = true; - } - - return true; -} - -template <typename DataType> -std::string GetServerId(const DataType& data) { - std::string server_id; - base::Base64Encode(data.server_id(), &server_id); - return server_id; -} - -} // namespace - -AutofillWalletMetadataSyncableService:: - ~AutofillWalletMetadataSyncableService() {} - -void AutofillWalletMetadataSyncableService::OnWalletDataTrackingStateChanged( - bool is_tracking) { - DCHECK_NE(track_wallet_data_, is_tracking); - track_wallet_data_ = is_tracking; - if (is_tracking && sync_processor_) { - MergeData(cache_); - } -} - -void AutofillWalletMetadataSyncableService::WaitUntilReadyToSync( - base::OnceClosure done) { - // Not used in the legacy directory-based architecture. - NOTREACHED(); -} - -syncer::SyncMergeResult -AutofillWalletMetadataSyncableService::MergeDataAndStartSyncing( - syncer::ModelType type, - const syncer::SyncDataList& initial_sync_data, - std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, - std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(!sync_processor_); - DCHECK(!sync_error_factory_); - DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type); - - sync_processor_ = std::move(sync_processor); - sync_error_factory_ = std::move(sync_error_factory); - - cache_ = initial_sync_data; - - syncer::SyncMergeResult result(syncer::AUTOFILL_WALLET_METADATA); - if (track_wallet_data_) { - result = MergeData(initial_sync_data); - } - - // Record ages for individual metadata entities to UMA. - for (const syncer::SyncData& data : cache_) { - const sync_pb::WalletMetadataSpecifics& specifics = - data.GetSpecifics().wallet_metadata(); - base::Time use_date = base::Time::FromDeltaSinceWindowsEpoch( - base::TimeDelta::FromMicroseconds(specifics.use_date())); - switch (specifics.type()) { - case sync_pb::WalletMetadataSpecifics::ADDRESS: - // TODO(crbug.com/949034): Consider adding standard functions for - // recording large times in seconds/minutes. - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Autofill.WalletUseDateInMinutes.Address", - /*sample=*/(AutofillClock::Now() - use_date).InMinutes(), - /*min=*/base::TimeDelta::FromMinutes(1).InMinutes(), - /*max=*/base::TimeDelta::FromDays(365).InMinutes(), - /*bucket_count=*/50); - break; - case sync_pb::WalletMetadataSpecifics::CARD: - // TODO(crbug.com/949034): Consider adding standard functions for - // recording large times in seconds/minutes. - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Autofill.WalletUseDateInMinutes.Card", - /*sample=*/(AutofillClock::Now() - use_date).InMinutes(), - /*min=*/base::TimeDelta::FromMinutes(1).InMinutes(), - /*max=*/base::TimeDelta::FromDays(365).InMinutes(), - /*bucket_count=*/50); - break; - case sync_pb::WalletMetadataSpecifics::UNKNOWN: - NOTREACHED(); - break; - } - } - - // Notify that sync has started. This callback does not currently take into - // account whether we're actually tracking wallet data. - if (web_data_backend_) - web_data_backend_->NotifyThatSyncHasStarted(type); - return result; -} - -void AutofillWalletMetadataSyncableService::StopSyncing( - syncer::ModelType type) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type); - - sync_processor_.reset(); - sync_error_factory_.reset(); - cache_.clear(); -} - -syncer::SyncDataList AutofillWalletMetadataSyncableService::GetAllSyncData( - syncer::ModelType type) const { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type); - - syncer::SyncDataList data_list; - std::unordered_map<std::string, std::unique_ptr<AutofillProfile>> profiles; - std::unordered_map<std::string, std::unique_ptr<CreditCard>> cards; - if (GetLocalData(&profiles, &cards)) { - for (const auto& it : profiles) { - data_list.push_back(BuildSyncData( - sync_pb::WalletMetadataSpecifics::ADDRESS, it.first, *it.second)); - } - - for (const auto& it : cards) { - data_list.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD, - it.first, *it.second)); - } - } - - return data_list; -} - -syncer::SyncError AutofillWalletMetadataSyncableService::ProcessSyncChanges( - const base::Location& from_here, - const syncer::SyncChangeList& changes_from_sync) { - DCHECK(thread_checker_.CalledOnValidThread()); - - ApplyChangesToCache(changes_from_sync, &cache_); - - // If we're not tracking wallet data, we can't rely on the local wallet - // data being up-to-date, so we should not do any merging with local data. - if (!track_wallet_data_) { - return syncer::SyncError(); - } - - std::unordered_map<std::string, std::unique_ptr<AutofillProfile>> profiles; - std::unordered_map<std::string, std::unique_ptr<CreditCard>> cards; - GetLocalData(&profiles, &cards); - - // base::Unretained is used because the callbacks are invoked synchronously. - base::Callback<bool(const AutofillProfile&)> address_updater = - base::Bind(&AutofillWalletMetadataSyncableService::UpdateAddressStats, - base::Unretained(this)); - base::Callback<bool(const CreditCard&)> card_updater = - base::Bind(&AutofillWalletMetadataSyncableService::UpdateCardStats, - base::Unretained(this)); - - bool is_any_local_modified = false; - - syncer::SyncChangeList changes_to_sync; - for (const syncer::SyncChange& change : changes_from_sync) { - const sync_pb::WalletMetadataSpecifics& remote_metadata = - change.sync_data().GetSpecifics().wallet_metadata(); - switch (change.change_type()) { - case syncer::SyncChange::ACTION_ADD: - // Intentional fall through. - case syncer::SyncChange::ACTION_UPDATE: - switch (remote_metadata.type()) { - case sync_pb::WalletMetadataSpecifics::ADDRESS: - MergeRemote(change.sync_data(), address_updater, - &is_any_local_modified, &profiles, &changes_to_sync); - break; - - case sync_pb::WalletMetadataSpecifics::CARD: - MergeRemote(change.sync_data(), card_updater, - &is_any_local_modified, &cards, &changes_to_sync); - break; - - case sync_pb::WalletMetadataSpecifics::UNKNOWN: - NOTREACHED(); - break; - } - break; - - // Metadata should only be deleted when the underlying data is deleted. - case syncer::SyncChange::ACTION_DELETE: - switch (remote_metadata.type()) { - case sync_pb::WalletMetadataSpecifics::ADDRESS: - UndeleteMetadataIfExisting( - remote_metadata.id(), sync_pb::WalletMetadataSpecifics::ADDRESS, - &profiles, &changes_to_sync); - break; - - case sync_pb::WalletMetadataSpecifics::CARD: - UndeleteMetadataIfExisting(remote_metadata.id(), - sync_pb::WalletMetadataSpecifics::CARD, - &cards, &changes_to_sync); - break; - - case sync_pb::WalletMetadataSpecifics::UNKNOWN: - NOTREACHED(); - break; - } - break; - - case syncer::SyncChange::ACTION_INVALID: - NOTREACHED(); - break; - } - } - - syncer::SyncError status; - if (!changes_to_sync.empty()) - status = SendChangesToSyncServer(changes_to_sync); - if (is_any_local_modified) { - // TODO(crbug.com/900607): Remove the need to listen to - // AutofillMultipleChangedBySync() in the new USS implementation so that we - // can get rid of this hack. - DCHECK(!ignore_multiple_changed_notification_); - ignore_multiple_changed_notification_ = true; - web_data_backend_->NotifyOfMultipleAutofillChanges(); - ignore_multiple_changed_notification_ = false; - } - - return status; -} - -void AutofillWalletMetadataSyncableService::AutofillProfileChanged( - const AutofillProfileChange& change) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(change.data_model()); - if (!track_wallet_data_) { - return; - } - - if (sync_processor_ && change.type() == AutofillProfileChange::UPDATE && - change.data_model()->record_type() != AutofillProfile::LOCAL_PROFILE) { - std::string server_id = GetServerId(*change.data_model()); - auto it = FindServerIdAndTypeInCache( - server_id, sync_pb::WalletMetadataSpecifics::ADDRESS, &cache_); - if (it == cache_.end()) - return; - - const sync_pb::WalletMetadataSpecifics& remote = - it->GetSpecifics().wallet_metadata(); - const AutofillProfile& local = *change.data_model(); - - - if (!AreLocalUseStatsUpdated(remote, local) && - !IsLocalHasConvertedStatusUpdated(remote, local)) { - return; - } - - SendChangesToSyncServer(syncer::SyncChangeList( - 1, syncer::SyncChange( - FROM_HERE, syncer::SyncChange::ACTION_UPDATE, - BuildSyncData(sync_pb::WalletMetadataSpecifics::ADDRESS, - server_id, local)))); - } -} - -void AutofillWalletMetadataSyncableService::CreditCardChanged( - const CreditCardChange& change) { - DCHECK(thread_checker_.CalledOnValidThread()); - if (!track_wallet_data_) { - return; - } - - if (sync_processor_ && change.data_model() && - change.data_model()->record_type() != CreditCard::LOCAL_CARD) { - std::string server_id = GetServerId(*change.data_model()); - auto it = FindServerIdAndTypeInCache( - server_id, sync_pb::WalletMetadataSpecifics::CARD, &cache_); - if (it == cache_.end()) - return; - // Deletions and creations are treated by Wallet data sync (and propagated - // here by AutofillMultipleChangedBySync()). We only treat updates here. - if (change.type() != AutofillProfileChange::UPDATE) { - return; - } - - const sync_pb::WalletMetadataSpecifics& remote = - it->GetSpecifics().wallet_metadata(); - const CreditCard& local = *change.data_model(); - if (!AreLocalUseStatsUpdated(remote, local) && - !IsLocalBillingAddressUpdated(remote, local)) { - return; - } - - SendChangesToSyncServer(syncer::SyncChangeList( - 1, - syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, - BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD, - server_id, local)))); - } -} - -void AutofillWalletMetadataSyncableService::AutofillMultipleChangedBySync() { - if (ignore_multiple_changed_notification_) { - // TODO(crbug.com/900607): Remove the need to listen to - // AutofillMultipleChangedBySync() in the new USS implementation so that we - // can get rid of this hack. - return; - } - - if (sync_processor_ && track_wallet_data_) - MergeData(cache_); -} - -// static -void AutofillWalletMetadataSyncableService::CreateForWebDataServiceAndBackend( - AutofillWebDataService* web_data_service, - AutofillWebDataBackend* web_data_backend, - const std::string& app_locale) { - web_data_service->GetDBUserData()->SetUserData( - AutofillWalletMetadataSyncableServiceUserDataKey(), - std::make_unique<AutofillWalletMetadataSyncableService>(web_data_backend, - app_locale)); -} - -// static -AutofillWalletMetadataSyncableService* -AutofillWalletMetadataSyncableService::FromWebDataService( - AutofillWebDataService* web_data_service) { - return static_cast<AutofillWalletMetadataSyncableService*>( - web_data_service->GetDBUserData()->GetUserData( - AutofillWalletMetadataSyncableServiceUserDataKey())); -} - -AutofillWalletMetadataSyncableService::AutofillWalletMetadataSyncableService( - AutofillWebDataBackend* web_data_backend, - const std::string& app_locale) - : web_data_backend_(web_data_backend), - scoped_observer_(this), - track_wallet_data_(false), - ignore_multiple_changed_notification_(false) { - scoped_observer_.Add(web_data_backend_); -} - -bool AutofillWalletMetadataSyncableService::GetLocalData( - std::unordered_map<std::string, std::unique_ptr<AutofillProfile>>* profiles, - std::unordered_map<std::string, std::unique_ptr<CreditCard>>* cards) const { - std::vector<std::unique_ptr<AutofillProfile>> profile_list; - bool success = - AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase()) - ->GetServerProfiles(&profile_list); - while (!profile_list.empty()) { - auto server_id = GetServerId(*profile_list.front()); - (*profiles)[server_id] = std::move(profile_list.front()); - profile_list.erase(profile_list.begin()); - } - - std::vector<std::unique_ptr<CreditCard>> card_list; - success &= AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase()) - ->GetServerCreditCards(&card_list); - while (!card_list.empty()) { - auto server_id = GetServerId(*card_list.front()); - (*cards)[server_id] = std::move(card_list.front()); - card_list.erase(card_list.begin()); - } - - return success; -} - -bool AutofillWalletMetadataSyncableService::UpdateAddressStats( - const AutofillProfile& profile) { - return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase()) - ->UpdateServerAddressMetadata(profile); -} - -bool AutofillWalletMetadataSyncableService::UpdateCardStats( - const CreditCard& credit_card) { - return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase()) - ->UpdateServerCardMetadata(credit_card); -} - -syncer::SyncError -AutofillWalletMetadataSyncableService::SendChangesToSyncServer( - const syncer::SyncChangeList& changes_to_sync) { - DCHECK(sync_processor_); - ApplyChangesToCache(changes_to_sync, &cache_); - return sync_processor_->ProcessSyncChanges(FROM_HERE, changes_to_sync); -} - -syncer::SyncMergeResult AutofillWalletMetadataSyncableService::MergeData( - const syncer::SyncDataList& sync_data) { - // If we're not tracking wallet data, we can't rely on the local wallet - // data being up-to-date, so we should not do any merging with local data. - DCHECK(track_wallet_data_); - - std::unordered_map<std::string, std::unique_ptr<AutofillProfile>> profiles; - std::unordered_map<std::string, std::unique_ptr<CreditCard>> cards; - GetLocalData(&profiles, &cards); - - syncer::SyncMergeResult result(syncer::AUTOFILL_WALLET_METADATA); - result.set_num_items_before_association(profiles.size() + cards.size()); - - // base::Unretained is used because the callbacks are invoked synchronously. - base::Callback<bool(const AutofillProfile&)> address_updater = - base::Bind(&AutofillWalletMetadataSyncableService::UpdateAddressStats, - base::Unretained(this)); - base::Callback<bool(const CreditCard&)> card_updater = - base::Bind(&AutofillWalletMetadataSyncableService::UpdateCardStats, - base::Unretained(this)); - - bool is_any_local_modified = false; - - syncer::SyncChangeList changes_to_sync; - for (const syncer::SyncData& remote : sync_data) { - DCHECK(remote.IsValid()); - DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, remote.GetDataType()); - switch (remote.GetSpecifics().wallet_metadata().type()) { - case sync_pb::WalletMetadataSpecifics::ADDRESS: - if (!MergeRemote(remote, address_updater, &is_any_local_modified, - &profiles, &changes_to_sync)) { - changes_to_sync.push_back(syncer::SyncChange( - FROM_HERE, syncer::SyncChange::ACTION_DELETE, remote)); - } - break; - - case sync_pb::WalletMetadataSpecifics::CARD: - if (!MergeRemote(remote, card_updater, &is_any_local_modified, &cards, - &changes_to_sync)) { - changes_to_sync.push_back(syncer::SyncChange( - FROM_HERE, syncer::SyncChange::ACTION_DELETE, remote)); - } - break; - - case sync_pb::WalletMetadataSpecifics::UNKNOWN: - NOTREACHED(); - break; - } - } - - // The remainder of |profiles| were not listed in |sync_data|. - for (const auto& it : profiles) { - changes_to_sync.push_back(syncer::SyncChange( - FROM_HERE, syncer::SyncChange::ACTION_ADD, - BuildSyncData(sync_pb::WalletMetadataSpecifics::ADDRESS, it.first, - *it.second))); - } - - // The remainder of |cards| were not listed in |sync_data|. - for (const auto& it : cards) { - changes_to_sync.push_back( - syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD, - BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD, - it.first, *it.second))); - } - - // The only operation that is performed locally in response to a sync is an - // update. Adds and deletes are performed in response to changes to the Wallet - // data. - result.set_num_items_after_association(result.num_items_before_association()); - result.set_num_items_added(0); - result.set_num_items_deleted(0); - - if (!changes_to_sync.empty()) - result.set_error(SendChangesToSyncServer(changes_to_sync)); - if (is_any_local_modified) { - // TODO(crbug.com/900607): Remove the need to listen to - // AutofillMultipleChangedBySync() in the new USS implementation so that we - // can get rid of this hack. - DCHECK(!ignore_multiple_changed_notification_); - ignore_multiple_changed_notification_ = true; - web_data_backend_->NotifyOfMultipleAutofillChanges(); - ignore_multiple_changed_notification_ = false; - } - - return result; -} - -} // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h deleted file mode 100644 index 25845d1..0000000 --- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h +++ /dev/null
@@ -1,162 +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. - -#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_ -#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_ - -#include <memory> -#include <string> -#include <unordered_map> - -#include "base/callback_forward.h" -#include "base/macros.h" -#include "base/scoped_observer.h" -#include "base/supports_user_data.h" -#include "base/threading/thread_checker.h" -#include "components/autofill/core/browser/webdata/autofill_change.h" -#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h" -#include "components/sync/model/sync_error.h" -#include "components/sync/model/sync_merge_result.h" -#include "components/sync/model/syncable_service.h" -#include "components/sync/protocol/autofill_specifics.pb.h" - -namespace base { -class Location; -} - -namespace syncer { -class SyncChangeProcessor; -class SyncErrorFactory; -} - -namespace autofill { - -class AutofillProfile; -class AutofillWebDataBackend; -class AutofillWebDataService; -class CreditCard; - -// Syncs usage counts and last use dates (metadata) for Wallet cards and -// addresses (data). -// -// The sync server generates the data, and the client can only download it. No -// data upload is possible. Chrome generates the corresponding metadata locally -// and uses the sync server to propagate the metadata to the other instances of -// Chrome. See the design doc at https://goo.gl/LS2y6M for more details. -class AutofillWalletMetadataSyncableService - : public base::SupportsUserData::Data, - public syncer::SyncableService, - public AutofillWebDataServiceObserverOnDBSequence { - public: - AutofillWalletMetadataSyncableService( - AutofillWebDataBackend* web_data_backend, - const std::string& app_locale); - - ~AutofillWalletMetadataSyncableService() override; - - // Determines whether this bridge should be monitoring the Wallet data. This - // should be called whenever the data bridge sync state changes. - void OnWalletDataTrackingStateChanged(bool is_tracking); - - base::WeakPtr<AutofillWalletMetadataSyncableService> GetWeakPtr() { - return weak_ptr_factory_.GetWeakPtr(); - } - - // syncer::SyncableService implementation. - void WaitUntilReadyToSync(base::OnceClosure done) override; - syncer::SyncMergeResult MergeDataAndStartSyncing( - syncer::ModelType type, - const syncer::SyncDataList& initial_sync_data, - std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, - std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) override; - void StopSyncing(syncer::ModelType type) override; - syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override; - syncer::SyncError ProcessSyncChanges( - const base::Location& from_here, - const syncer::SyncChangeList& changes_from_sync) override; - - // AutofillWebDataServiceObserverOnDBSequence implementation. - void AutofillProfileChanged(const AutofillProfileChange& change) override; - void CreditCardChanged(const CreditCardChange& change) override; - void AutofillMultipleChangedBySync() override; - - // Creates a new AutofillWalletMetadataSyncableService and hangs it off of - // |web_data_service|, which takes ownership. This method should only be - // called on |web_data_service|'s DB sequence. |web_data_backend| is expected - // to outlive this object. - static void CreateForWebDataServiceAndBackend( - AutofillWebDataService* web_data_service, - AutofillWebDataBackend* web_data_backend, - const std::string& app_locale); - - // Retrieves the AutofillWalletMetadataSyncableService stored on - // |web_data_service|. - static AutofillWalletMetadataSyncableService* FromWebDataService( - AutofillWebDataService* web_data_service); - - protected: - // Populates the provided |profiles| and |cards| with mappings from server ID - // to server profiles and server cards read from disk. This data contains the - // usage stats. Returns true on success. - virtual bool GetLocalData( - std::unordered_map<std::string, std::unique_ptr<AutofillProfile>>* - profiles, - std::unordered_map<std::string, std::unique_ptr<CreditCard>>* cards) - const; - - // Updates the stats for |profile| stored on disk. Does not trigger - // notifications that this profile was updated. - virtual bool UpdateAddressStats(const AutofillProfile& profile); - - // Updates the stats for |credit_card| stored on disk. Does not trigger - // notifications that this credit card was updated. - virtual bool UpdateCardStats(const CreditCard& credit_card); - - // Sends the |changes_to_sync| to the sync server. - virtual syncer::SyncError SendChangesToSyncServer( - const syncer::SyncChangeList& changes_to_sync); - - private: - // Merges local metadata with |sync_data|. - // - // Sends an "update" to the sync server if |sync_data| contains metadata that - // is present locally, but local metadata has higher use count and later use - // date. - // - // Sends a "create" to the sync server if |sync_data| does not have some local - // metadata. - // - // Sends a "delete" to the sync server if |sync_data| contains metadata that - // is not present locally. - syncer::SyncMergeResult MergeData(const syncer::SyncDataList& sync_data); - - base::ThreadChecker thread_checker_; - AutofillWebDataBackend* web_data_backend_; // Weak ref. - ScopedObserver<AutofillWebDataBackend, AutofillWalletMetadataSyncableService> - scoped_observer_; - std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_; - std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory_; - - // Local metadata plus metadata for the data that hasn't synced down yet. - syncer::SyncDataList cache_; - - // Indicates whether we should rely on wallet data being actively synced. If - // true, the service will prune metadata entries without corresponding wallet - // data entry. - bool track_wallet_data_; - - // Indicates that we should ignore multiple changed notification. This is used - // to block reflection and not to act on notification that we've triggered - // ourselves. - bool ignore_multiple_changed_notification_; - - base::WeakPtrFactory<AutofillWalletMetadataSyncableService> weak_ptr_factory_{ - this}; - - DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncableService); -}; - -} // namespace autofill - -#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc deleted file mode 100644 index eda11ce..0000000 --- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc +++ /dev/null
@@ -1,1366 +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. - -#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h" - -#include <stddef.h> -#include <stdint.h> - -#include <memory> -#include <utility> -#include <vector> - -#include "base/base64.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/numerics/safe_conversions.h" -#include "base/time/time.h" -#include "components/autofill/core/browser/data_model/autofill_profile.h" -#include "components/autofill/core/browser/data_model/credit_card.h" -#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" -#include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h" -#include "components/sync/model/sync_change.h" -#include "components/sync/model/sync_change_processor_wrapper_for_test.h" -#include "components/sync/model/sync_error_factory_mock.h" -#include "components/sync/protocol/autofill_specifics.pb.h" -#include "components/sync/protocol/sync.pb.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace autofill { -namespace { - -using testing::DoAll; -using testing::ElementsAre; -using testing::Invoke; -using testing::NiceMock; -using testing::Return; -using testing::Test; -using testing::UnorderedElementsAre; -using testing::Value; -using testing::_; - -// Non-UTF8 server IDs. -const char kAddr1[] = "addr1\xEF\xBF\xBE"; -const char kAddr2[] = "addr2\xEF\xBF\xBE"; -const char kCard1[] = "card1\xEF\xBF\xBE"; -const char kCard2[] = "card2\xEF\xBF\xBE"; - -// Base64 encodings of the server IDs. These are suitable for syncing, because -// they are valid UTF-8. -const char kAddr1Utf8[] = "YWRkcjHvv74="; -const char kAddr2Utf8[] = "YWRkcjLvv74="; -const char kCard1Utf8[] = "Y2FyZDHvv74="; -const char kCard2Utf8[] = "Y2FyZDLvv74="; - -// Unique sync tags for the server IDs. -const char kAddr1SyncTag[] = "address-YWRkcjHvv74="; -const char kAddr2SyncTag[] = "address-YWRkcjLvv74="; -const char kCard1SyncTag[] = "card-Y2FyZDHvv74="; -const char kCard2SyncTag[] = "card-Y2FyZDLvv74="; - -// Local profile GUID in UTF8 and non-UTF8. -const char kLocalAddr1[] = "e171e3ed-858a-4dd5-9bf3-8517f14ba5fc"; -const char kLocalAddr2[] = "fa232b9a-f248-4e5a-8d76-d46f821c0c5f"; -const char kLocalAddr1Utf8[] = - "ZTE3MWUzZWQtODU4YS00ZGQ1LTliZjMtODUxN2YxNGJhNWZj"; - -// Map values are owned by the caller to GetLocalData. -ACTION_P2(GetCopiesOf, profiles, cards) { - for (const auto& profile : *profiles) { - std::string utf8_server_id; - base::Base64Encode(profile.server_id(), &utf8_server_id); - (*arg0)[utf8_server_id] = std::make_unique<AutofillProfile>(profile); - } - - for (const auto& card : *cards) { - std::string utf8_server_id; - base::Base64Encode(card.server_id(), &utf8_server_id); - (*arg1)[utf8_server_id] = std::make_unique<CreditCard>(card); - } -} - -ACTION_P(SaveDataIn, list) { - for (auto& item : *list) { - if (item.server_id() == arg0.server_id()) { - item = arg0; - return; - } - } - - list->push_back(arg0); -} - -// A syncable service for Wallet metadata that mocks out disk IO. -class MockService : public AutofillWalletMetadataSyncableService { - public: - MockService(AutofillWebDataBackend* web_data_backend) - : AutofillWalletMetadataSyncableService(web_data_backend, std::string()) { - ON_CALL(*this, GetLocalData(_, _)) - .WillByDefault(DoAll(GetCopiesOf(&server_profiles_, &server_cards_), - Return(true))); - - ON_CALL(*this, UpdateAddressStats(_)) - .WillByDefault(DoAll(SaveDataIn(&server_profiles_), Return(true))); - - ON_CALL(*this, UpdateCardStats(_)) - .WillByDefault(DoAll(SaveDataIn(&server_cards_), Return(true))); - - ON_CALL(*this, SendChangesToSyncServer(_)) - .WillByDefault( - Invoke(this, &MockService::SendChangesToSyncServerConcrete)); - } - - ~MockService() override {} - - MOCK_METHOD1(UpdateAddressStats, bool(const AutofillProfile&)); - MOCK_METHOD1(UpdateCardStats, bool(const CreditCard&)); - MOCK_METHOD1(SendChangesToSyncServer, - syncer::SyncError(const syncer::SyncChangeList&)); - - void ClearServerData() { - server_profiles_.clear(); - server_cards_.clear(); - } - - private: - MOCK_CONST_METHOD2( - GetLocalData, - bool(std::unordered_map<std::string, std::unique_ptr<AutofillProfile>>*, - std::unordered_map<std::string, std::unique_ptr<CreditCard>>*)); - - syncer::SyncError SendChangesToSyncServerConcrete( - const syncer::SyncChangeList& changes) { - return AutofillWalletMetadataSyncableService::SendChangesToSyncServer( - changes); - } - - syncer::SyncDataList GetAllSyncDataConcrete(syncer::ModelType type) const { - return AutofillWalletMetadataSyncableService::GetAllSyncData(type); - } - - std::vector<AutofillProfile> server_profiles_; - std::vector<CreditCard> server_cards_; - - DISALLOW_COPY_AND_ASSIGN(MockService); -}; - -class AutofillWalletMetadataSyncableServiceTest : public Test { - public: - AutofillWalletMetadataSyncableServiceTest() - : local_(&backend_), remote_(&backend_) {} - ~AutofillWalletMetadataSyncableServiceTest() override {} - - void SetUp() { - local_.OnWalletDataTrackingStateChanged(true); - remote_.OnWalletDataTrackingStateChanged(true); - } - - // Outlives local_ and remote_. - NiceMock<MockAutofillWebDataBackend> backend_; - - // Outlived by backend_. - NiceMock<MockService> local_; - NiceMock<MockService> remote_; - - private: - DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncableServiceTest); -}; - -// Verify that nothing is sent to the sync server when there's no metadata on -// disk. -TEST_F(AutofillWalletMetadataSyncableServiceTest, NoMetadataToReturn) { - EXPECT_TRUE(local_.GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA).empty()); -} - -AutofillProfile BuildAddress(const std::string& server_id, - int64_t use_count, - int64_t use_date, - bool has_converted) { - AutofillProfile profile(AutofillProfile::SERVER_PROFILE, server_id); - profile.set_use_count(use_count); - profile.set_use_date(base::Time::FromInternalValue(use_date)); - profile.set_has_converted(has_converted); - return profile; -} - -CreditCard BuildCard(const std::string& server_id, - int64_t use_count, - int64_t use_date, - const std::string& billing_address_id) { - CreditCard card(CreditCard::MASKED_SERVER_CARD, server_id); - card.set_use_count(use_count); - card.set_use_date(base::Time::FromInternalValue(use_date)); - card.set_billing_address_id(billing_address_id); - return card; -} - -MATCHER_P6(SyncAddressDataMatches, - sync_tag, - metadata_type, - server_id, - use_count, - use_date, - has_converted, - "") { - return arg.IsValid() && - syncer::AUTOFILL_WALLET_METADATA == arg.GetDataType() && - sync_tag == syncer::SyncDataLocal(arg).GetTag() && - metadata_type == arg.GetSpecifics().wallet_metadata().type() && - server_id == arg.GetSpecifics().wallet_metadata().id() && - use_count == arg.GetSpecifics().wallet_metadata().use_count() && - use_date == arg.GetSpecifics().wallet_metadata().use_date() && - has_converted == - arg.GetSpecifics().wallet_metadata().address_has_converted(); -} - -MATCHER_P6(SyncCardDataMatches, - sync_tag, - metadata_type, - server_id, - use_count, - use_date, - billing_address_id, - "") { - return arg.IsValid() && - syncer::AUTOFILL_WALLET_METADATA == arg.GetDataType() && - sync_tag == syncer::SyncDataLocal(arg).GetTag() && - metadata_type == arg.GetSpecifics().wallet_metadata().type() && - server_id == arg.GetSpecifics().wallet_metadata().id() && - use_count == arg.GetSpecifics().wallet_metadata().use_count() && - use_date == arg.GetSpecifics().wallet_metadata().use_date() && - billing_address_id == - arg.GetSpecifics().wallet_metadata().card_billing_address_id(); -} - -// Verify that all metadata from disk is sent to the sync server. -TEST_F(AutofillWalletMetadataSyncableServiceTest, ReturnAllMetadata) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - - EXPECT_THAT(local_.GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA), - UnorderedElementsAre( - SyncAddressDataMatches( - kAddr1SyncTag, sync_pb::WalletMetadataSpecifics::ADDRESS, - kAddr1Utf8, 1, 2, true), - SyncCardDataMatches(kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 3, 4, kAddr1Utf8))); -} - -void MergeMetadata(MockService* local, MockService* remote) { - // The wrapper for |remote| gives it a null change processor, so sending - // changes is not possible. - ON_CALL(*remote, SendChangesToSyncServer(_)) - .WillByDefault(Return(syncer::SyncError())); - - std::unique_ptr<syncer::SyncErrorFactoryMock> errors( - new syncer::SyncErrorFactoryMock); - EXPECT_CALL(*errors, CreateAndUploadError(_, _)).Times(0); - EXPECT_FALSE( - local - ->MergeDataAndStartSyncing( - syncer::AUTOFILL_WALLET_METADATA, - remote->GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA), - std::unique_ptr<syncer::SyncChangeProcessor>( - new syncer::SyncChangeProcessorWrapperForTest(remote)), - std::move(errors)) - .error() - .IsSet()); -} - -// Verify that nothing is written to disk or sent to the sync server when two -// empty clients are syncing. -TEST_F(AutofillWalletMetadataSyncableServiceTest, TwoEmptyClients) { - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - MergeMetadata(&local_, &remote_); -} - -MATCHER_P2(SyncChangeMatches, change_type, sync_tag, "") { - return arg.IsValid() && change_type == arg.change_type() && - sync_tag == syncer::SyncDataLocal(arg.sync_data()).GetTag() && - syncer::AUTOFILL_WALLET_METADATA == arg.sync_data().GetDataType(); -} - -// Verify that remote data without local counterpart is deleted during the -// initial merge. -TEST_F(AutofillWalletMetadataSyncableServiceTest, DeleteFromServerOnMerge) { - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL( - local_, - SendChangesToSyncServer(UnorderedElementsAre( - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag), - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, - kCard1SyncTag)))); - - MergeMetadata(&local_, &remote_); -} - -// Verify that remote data without local counterpart is kept when we're not -// tracking wallet data. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DeleteFromServerOnMerge_NotWhenNotTracking) { - local_.OnWalletDataTrackingStateChanged(false); - - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - MergeMetadata(&local_, &remote_); -} - -// Verify that remote data without local counterpart is deleted when we start -// tracking wallet data after the initial merge happened. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DeleteFromServerOnMerge_MergeBeforeTracking) { - local_.OnWalletDataTrackingStateChanged(false); - - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL( - local_, - SendChangesToSyncServer(UnorderedElementsAre( - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag), - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, - kCard1SyncTag)))); - - MergeMetadata(&local_, &remote_); - - local_.OnWalletDataTrackingStateChanged(true); -} - -MATCHER_P7(SyncAddressChangeAndDataMatch, - change_type, - sync_tag, - metadata_type, - server_id, - use_count, - use_date, - has_converted, - "") { - return Value(arg, SyncChangeMatches(change_type, sync_tag)) && - Value(arg.sync_data(), - SyncAddressDataMatches(sync_tag, metadata_type, server_id, - use_count, use_date, has_converted)); -} - -MATCHER_P7(SyncCardChangeAndDataMatch, - change_type, - sync_tag, - metadata_type, - server_id, - use_count, - use_date, - billing_address_id, - "") { - return Value(arg, SyncChangeMatches(change_type, sync_tag)) && - Value(arg.sync_data(), - SyncCardDataMatches(sync_tag, metadata_type, server_id, - use_count, use_date, billing_address_id)); -} - -// Verify that local data is sent to the sync server during the initial merge, -// if the server does not have the data already. -TEST_F(AutofillWalletMetadataSyncableServiceTest, AddToServerOnMerge) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre( - SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_ADD, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, - kAddr1Utf8, 1, 2, true), - SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_ADD, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 3, 4, kAddr1Utf8)))); - - MergeMetadata(&local_, &remote_); -} - -// Verify that no data is written to disk or sent to the sync server if the -// local and remote data are identical during the initial merge. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - IgnoreIdenticalValuesOnMerge) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - MergeMetadata(&local_, &remote_); -} - -MATCHER_P4(AutofillAddressMetadataMatches, - server_id, - use_count, - use_date, - has_converted, - "") { - return arg.server_id() == server_id && - arg.use_count() == base::checked_cast<size_t>(use_count) && - arg.use_date() == base::Time::FromInternalValue(use_date) && - arg.has_converted() == has_converted; -} - -MATCHER_P4(AutofillCardMetadataMatches, - server_id, - use_count, - use_date, - billing_address_id, - "") { - return arg.server_id() == server_id && - arg.use_count() == base::checked_cast<size_t>(use_count) && - arg.use_date() == base::Time::FromInternalValue(use_date) && - arg.billing_address_id() == billing_address_id; -} - -// Verify that remote data with higher values of use count and last use date is -// saved to disk during the initial merge. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - SaveHigherValuesLocallyOnMerge) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 10, 20, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 30, 40, kAddr1)); - - EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches( - kAddr1, 10, 20, true))); - EXPECT_CALL(local_, UpdateCardStats( - AutofillCardMetadataMatches(kCard1, 30, 40, kAddr1))); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - MergeMetadata(&local_, &remote_); -} - -// Verify that local data with higher values of use count and last use date is -// sent to the sync server during the initial merge. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - SendHigherValuesToServerOnMerge) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 10, 20, true)); - local_.UpdateCardStats(BuildCard(kCard1, 30, 40, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr2)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre( - SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, - kAddr1Utf8, 10, 20, true), - SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 30, 40, kAddr1Utf8)))); - - MergeMetadata(&local_, &remote_); -} - -// Verify that lower or equal values of metadata are not sent to the sync server -// when local metadata is updated. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DontSendLowerValueToServerOnSingleChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - AutofillProfile address = BuildAddress(kAddr1, 0, 0, true); - CreditCard card = BuildCard(kCard1, 3, 4, kAddr1); - - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::UPDATE, address.guid(), &address)); - local_.CreditCardChanged( - CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card)); -} - -// Verify that higher values of metadata are sent to the sync server when local -// metadata is updated. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - SendHigherValuesToServerOnLocalSingleChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - AutofillProfile address = BuildAddress(kAddr1, 10, 20, true); - CreditCard card = BuildCard(kCard1, 30, 40, kAddr2); - - EXPECT_CALL(local_, - SendChangesToSyncServer(ElementsAre(SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 10, 20, - true)))); - EXPECT_CALL(local_, - SendChangesToSyncServer(ElementsAre(SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 30, 40, - kAddr2Utf8)))); - - local_.AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::UPDATE, address.guid(), &address)); - local_.CreditCardChanged( - CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card)); -} - -// Verify that other changed metadata elements are sent to the sync server when -// local metadata is updated. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - SendChangedMetadataToServerOnLocalSingleChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - AutofillProfile address = BuildAddress(kAddr1, 1, 2, true); - CreditCard card = BuildCard(kCard1, 3, 4, kAddr2); - - EXPECT_CALL( - local_, - SendChangesToSyncServer(ElementsAre(SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 1, 2, true)))); - EXPECT_CALL(local_, - SendChangesToSyncServer(ElementsAre(SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 3, 4, - kAddr2Utf8)))); - - local_.AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::UPDATE, address.guid(), &address)); - local_.CreditCardChanged( - CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card)); -} - -// Verify that one-off addition of metadata is not sent to the sync -// server. Metadata add and delete trigger multiple changes notification -// instead. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DontAddToServerOnSingleChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - AutofillProfile address = BuildAddress(kAddr2, 5, 6, false); - CreditCard card = BuildCard(kCard2, 7, 8, kAddr2); - - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.AutofillProfileChanged(AutofillProfileChange( - AutofillProfileChange::UPDATE, address.guid(), &address)); - local_.CreditCardChanged( - CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card)); -} - -// Verify that new metadata is sent to the sync server when multiple metadata -// values change at once. -TEST_F(AutofillWalletMetadataSyncableServiceTest, AddToServerOnMultiChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - // These methods do not trigger notifications or sync: - local_.UpdateAddressStats(BuildAddress(kAddr2, 5, 6, true)); - local_.UpdateCardStats(BuildCard(kCard2, 7, 8, kAddr2)); - - EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre( - SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_ADD, kAddr2SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, - kAddr2Utf8, 5, 6, true), - SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_ADD, kCard2SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard2Utf8, 7, 8, kAddr2Utf8)))); - - local_.AutofillMultipleChangedBySync(); -} - -// Verify that higher values of existing metadata are sent to the sync server -// when multiple metadata values change at once. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - UpdateToHigherValueOnServerOnMultiChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - // These methods do not trigger notifications or sync: - local_.UpdateAddressStats(BuildAddress(kAddr1, 5, 6, true)); - local_.UpdateCardStats(BuildCard(kCard1, 7, 8, kAddr2)); - - EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre( - SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, - kAddr1Utf8, 5, 6, true), - SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 7, 8, kAddr2Utf8)))); - - local_.AutofillMultipleChangedBySync(); -} - -// Verify that lower values of existing metadata are not sent to the sync server -// when multiple metadata values change at once. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DontUpdateToLowerValueOnServerOnMultiChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - // These methods do not trigger notifications or sync: - local_.UpdateAddressStats(BuildAddress(kAddr1, 0, 0, false)); - local_.UpdateCardStats(BuildCard(kCard1, 0, 0, kAddr2)); - - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.AutofillMultipleChangedBySync(); -} - -// Verify that erased local metadata is also erased from the sync server when -// multiple metadata values change at once. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DeleteFromServerOnMultiChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - // This method dooes not trigger notifications or sync: - local_.ClearServerData(); - - EXPECT_CALL( - local_, - SendChangesToSyncServer(UnorderedElementsAre( - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag), - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, - kCard1SyncTag)))); - - local_.AutofillMultipleChangedBySync(); -} - -// Verify that erased local metadata is not erased from the sync server when -// the service is not tracking Wallet data. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DeleteFromServerOnMultiChange_NotWhenNotTracking) { - local_.OnWalletDataTrackingStateChanged(false); - - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - // This method dooes not trigger notifications or sync: - local_.ClearServerData(); - - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.AutofillMultipleChangedBySync(); -} - -// Verify that erased local metadata is also erased from the sync server when -// we start tracking Wallet data after multiple metadata values change at once. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DeleteFromServerOnMultiChange_ChangeBeforeTracking) { - local_.OnWalletDataTrackingStateChanged(false); - - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - // This method dooes not trigger notifications or sync: - local_.ClearServerData(); - - EXPECT_CALL( - local_, - SendChangesToSyncServer(UnorderedElementsAre( - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag), - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, - kCard1SyncTag)))); - - local_.AutofillMultipleChangedBySync(); - local_.OnWalletDataTrackingStateChanged(true); -} - -// Verify that empty sync change from the sync server does not trigger writing -// to disk or sending any data to the sync server. -TEST_F(AutofillWalletMetadataSyncableServiceTest, EmptySyncChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.ProcessSyncChanges(FROM_HERE, syncer::SyncChangeList()); -} - -void BuildBasicChange(syncer::SyncChange::SyncChangeType change_type, - const std::string& sync_tag, - sync_pb::WalletMetadataSpecifics::Type metadata_type, - const std::string& server_id, - int64_t use_count, - int64_t use_date, - sync_pb::EntitySpecifics* entity) { - entity->mutable_wallet_metadata()->set_type(metadata_type); - entity->mutable_wallet_metadata()->set_id(server_id); - entity->mutable_wallet_metadata()->set_use_count(use_count); - entity->mutable_wallet_metadata()->set_use_date(use_date); -} - -syncer::SyncChange BuildAddressChange( - syncer::SyncChange::SyncChangeType change_type, - const std::string& sync_tag, - sync_pb::WalletMetadataSpecifics::Type metadata_type, - const std::string& server_id, - int64_t use_count, - int64_t use_date, - bool has_converted) { - sync_pb::EntitySpecifics entity; - BuildBasicChange(change_type, sync_tag, metadata_type, server_id, use_count, - use_date, &entity); - entity.mutable_wallet_metadata()->set_address_has_converted(has_converted); - return syncer::SyncChange( - FROM_HERE, change_type, - syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity)); -} - -syncer::SyncChange BuildCardChange( - syncer::SyncChange::SyncChangeType change_type, - const std::string& sync_tag, - sync_pb::WalletMetadataSpecifics::Type metadata_type, - const std::string& server_id, - int64_t use_count, - int64_t use_date, - const std::string& billing_address_id) { - sync_pb::EntitySpecifics entity; - BuildBasicChange(change_type, sync_tag, metadata_type, server_id, use_count, - use_date, &entity); - entity.mutable_wallet_metadata()->set_card_billing_address_id( - billing_address_id); - return syncer::SyncChange( - FROM_HERE, change_type, - syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity)); -} - -// Verify that new metadata from the sync server is ignored when processing -// on-going sync changes. There should be no disk writes or messages to the sync -// server. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - IgnoreNewMetadataFromServerOnSyncChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_ADD, kAddr2SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr2Utf8, 5, 6, true)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_ADD, kCard2SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard2Utf8, 7, 8, kAddr2Utf8)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.ProcessSyncChanges(FROM_HERE, changes); -} - -// Verify that higher values of metadata from the sync server are saved to -// disk when processing on-going sync changes. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - SaveHigherValuesFromServerOnSyncChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, false)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, false)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 10, 20, true)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 30, 40, kAddr2Utf8)); - - EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches( - kAddr1, 10, 20, true))); - EXPECT_CALL(local_, UpdateCardStats( - AutofillCardMetadataMatches(kCard1, 30, 40, kAddr2))); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.ProcessSyncChanges(FROM_HERE, changes); -} - -// Verify that higher local values of metadata are sent to the sync server when -// processing on-going sync changes. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - SendHigherValuesToServerOnSyncChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 0, 0, false)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 0, 0, kAddr2Utf8)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre( - SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, - kAddr1Utf8, 2, 2, true), - SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 3, 4, kAddr1Utf8)))); - - local_.ProcessSyncChanges(FROM_HERE, changes); -} - -// Verify that addition of known metadata is treated the same as an update. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - TreatAdditionOfKnownMetadataAsUpdateOnSyncChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_ADD, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 0, 0, false)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_ADD, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 0, 0, kAddr2Utf8)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre( - SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, - kAddr1Utf8, 2, 2, true), - SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 3, 4, kAddr1Utf8)))); - - local_.ProcessSyncChanges(FROM_HERE, changes); -} - -// Verify that an update of locally unknown metadata is ignored. There should be -// no disk writes and no messages sent to the server. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - IgnoreUpdateOfUnknownMetadataOnSyncChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_UPDATE, kAddr2SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr2Utf8, 0, 0, false)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_UPDATE, kCard2SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard2Utf8, 0, 0, kAddr2Utf8)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.ProcessSyncChanges(FROM_HERE, changes); -} - -// Verify that deletion from the sync server of locally unknown metadata is -// ignored. There should be no disk writes and no messages sent to the server. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - IgnoreDeleteOfUnknownMetadataOnSyncChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_DELETE, kAddr2SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr2Utf8, 0, 0, false)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_DELETE, kCard2SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard2Utf8, 0, 0, kAddr2Utf8)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.ProcessSyncChanges(FROM_HERE, changes); -} - -// Verify that deletion from the sync server of locally existing metadata will -// trigger an undelete message sent to the server. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - UndeleteExistingMetadataOnSyncChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - MergeMetadata(&local_, &remote_); - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 0, 0, false)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_DELETE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 0, 0, kAddr2Utf8)); - - EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0); - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre( - SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_ADD, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, - kAddr1Utf8, 2, 2, true), - SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_ADD, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 3, 4, kAddr1Utf8)))); - - local_.ProcessSyncChanges(FROM_HERE, changes); -} - -// Verify that processing sync changes maintains the local cache of sync server -// data, which is used to avoid calling the expensive GetAllSyncData() function. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - CacheIsUpToDateAfterSyncChange) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - local_.UpdateAddressStats(BuildAddress(kAddr2, 3, 4, false)); - local_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1)); - local_.UpdateCardStats(BuildCard(kCard2, 7, 8, kAddr2)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - remote_.UpdateAddressStats(BuildAddress(kAddr2, 3, 4, false)); - remote_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1)); - remote_.UpdateCardStats(BuildCard(kCard2, 7, 8, kAddr2)); - MergeMetadata(&local_, &remote_); - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 10, 20, false)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 50, 60, kAddr1Utf8)); - local_.ProcessSyncChanges(FROM_HERE, changes); - // This method dooes not trigger notifications or sync: - local_.ClearServerData(); - - EXPECT_CALL( - local_, - SendChangesToSyncServer(UnorderedElementsAre( - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag), - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr2SyncTag), - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kCard1SyncTag), - SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, - kCard2SyncTag)))); - - local_.AutofillMultipleChangedBySync(); -} - -// Verify that Wallet data arriving after metadata will not send lower metadata -// values to the sync server. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - SaveHigherValuesLocallyOnLateDataArrival) { - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, false)); - remote_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1)); - MergeMetadata(&local_, &remote_); - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 5, 6, true)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 7, 8, kAddr2Utf8)); - local_.ProcessSyncChanges(FROM_HERE, changes); - local_.UpdateAddressStats(BuildAddress(kAddr1, 0, 0, true)); - local_.UpdateCardStats(BuildCard(kCard1, 0, 0, kAddr2)); - - EXPECT_CALL(local_, UpdateAddressStats( - AutofillAddressMetadataMatches(kAddr1, 5, 6, true))); - EXPECT_CALL(local_, UpdateCardStats( - AutofillCardMetadataMatches(kCard1, 7, 8, kAddr2))); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.AutofillMultipleChangedBySync(); -} - -// Verify that processing a small subset of metadata changes before any Wallet -// data arrived will not cause sending lower metadata values to the sync server -// once the data finally arrives. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - SaveHigherValuesLocallyOnLateDataArrivalAfterPartialUpdates) { - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, false)); - remote_.UpdateAddressStats(BuildAddress(kAddr2, 3, 4, false)); - remote_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1)); - remote_.UpdateCardStats(BuildCard(kCard2, 7, 8, kAddr1)); - MergeMetadata(&local_, &remote_); - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 9, 10, false)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 11, 12, kAddr2Utf8)); - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_UPDATE, kAddr2SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr2Utf8, 13, 14, true)); - changes.push_back(BuildCardChange( - syncer::SyncChange::ACTION_UPDATE, kCard2SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, kCard2Utf8, 15, 16, kAddr1Utf8)); - local_.ProcessSyncChanges(FROM_HERE, changes); - changes.resize(2); - local_.ProcessSyncChanges(FROM_HERE, changes); - local_.UpdateAddressStats(BuildAddress(kAddr1, 0, 0, false)); - local_.UpdateAddressStats(BuildAddress(kAddr2, 0, 0, false)); - local_.UpdateCardStats(BuildCard(kCard1, 0, 0, kAddr1)); - local_.UpdateCardStats(BuildCard(kCard2, 0, 0, kAddr2)); - - EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches( - kAddr1, 9, 10, false))); - EXPECT_CALL(local_, UpdateCardStats( - AutofillCardMetadataMatches(kCard1, 11, 12, kAddr2))); - EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches( - kAddr2, 13, 14, true))); - EXPECT_CALL(local_, UpdateCardStats( - AutofillCardMetadataMatches(kCard2, 15, 16, kAddr1))); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.AutofillMultipleChangedBySync(); -} - -// Verify that the merge logic keeps the best data on a field by field basis. -// Make sure that if the better data is split across the local and server -// version, both are updated with the merge results. -TEST_F(AutofillWalletMetadataSyncableServiceTest, SaveHigherValues_Mixed1) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 20, true)); - local_.UpdateCardStats(BuildCard(kCard1, 30, 4, "")); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 10, 2, false)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 40, kAddr1)); - - EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches( - kAddr1, 10, 20, true))); - EXPECT_CALL(local_, UpdateCardStats( - AutofillCardMetadataMatches(kCard1, 30, 40, kAddr1))); - EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre( - SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, - kAddr1Utf8, 10, 20, true), - SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 30, 40, kAddr1Utf8)))); - - MergeMetadata(&local_, &remote_); -} - -// Verify that the merge logic keeps the best data on a field by field basis. -// Make sure that if the better data is split across the local and server -// version, both are updated with the merge results. -// Same as SaveHigherValues_Mixed1 but with the higher values moved from local -// to server and vice versa. -TEST_F(AutofillWalletMetadataSyncableServiceTest, SaveHigherValues_Mixed2) { - local_.UpdateAddressStats(BuildAddress(kAddr1, 10, 2, false)); - local_.UpdateCardStats(BuildCard(kCard1, 3, 40, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 20, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 30, 4, "")); - - EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches( - kAddr1, 10, 20, true))); - EXPECT_CALL(local_, UpdateCardStats( - AutofillCardMetadataMatches(kCard1, 30, 40, kAddr1))); - EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre( - SyncAddressChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, - kAddr1Utf8, 10, 20, true), - SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 30, 40, kAddr1Utf8)))); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if both local and server have a different non empty billing -// address id refering to a Wallet address, the one with the most recent -// (bigger) use date is kept. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DifferentServerBillingAddressId_LocalMostRecent) { - local_.UpdateCardStats(BuildCard(kCard1, 3, 40, kAddr1)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr2)); - - // The value from the local should be kept because it has a more recent use - // date. - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer( - UnorderedElementsAre(SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 3, 40, kAddr1Utf8)))); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if both local and server have a different non empty billing -// address id refering to a Wallet address, the one with the most recent -// (bigger) use date is kept. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DifferentServerBillingAddressId_RemoteMostRecent) { - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 40, kAddr2)); - - // The value from the remote should be kept because it has a more recent use - // date. - EXPECT_CALL(local_, UpdateCardStats( - AutofillCardMetadataMatches(kCard1, 3, 40, kAddr2))); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if both local and server have a different non empty billing -// address id refering to a local profile, the one with the most recent (bigger) -// use date is kept. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DifferentLocalBillingAddressId_LocalMostRecent) { - local_.UpdateCardStats(BuildCard(kCard1, 3, 40, kLocalAddr1)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr2)); - - // The value from the local should be kept because it has a more recent use - // date. - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer( - UnorderedElementsAre(SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 3, 40, kLocalAddr1Utf8)))); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if both local and server have a different non empty billing -// address id refering to a local profile, the one with the most recent (bigger) -// use date is kept. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DifferentLocalBillingAddressId_RemoteMostRecent) { - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 40, kLocalAddr2)); - - // The value from the remote should be kept because it has a more recent use - // date. - EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches( - kCard1, 3, 40, kLocalAddr2))); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if both local and server have a different non empty billing -// address id, the one refering to a local profile is always kept. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DifferentBillingAddressId_KeepLocalId_Local) { - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr2)); - - // The billing address from the local version of the card should be kept since - // it refers to a local autofill profile. - EXPECT_CALL(local_, UpdateCardStats(_)).Times(0); - EXPECT_CALL(local_, SendChangesToSyncServer( - UnorderedElementsAre(SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 3, 4, kLocalAddr1Utf8)))); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if both local and server have a different non empty billing -// address id, the one refering to a local profile is always kept, even id the -// other was used more recently. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DifferentBillingAddressId_KeepLocalId_Remote) { - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr2)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1)); - - // The billing address from the remote version of the card should be kept - // since it refers to a local autofill profile. - EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches( - kCard1, 3, 4, kLocalAddr1))); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if both local and server have a different non empty billing -// address id, the one refering to a local profile is always kept, even id the -// other was used more recently. Also makes sure that for the rest of the fields -// the highest values are kept. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - SaveHigherValues_DifferentBillingAddressId_KeepLocalId_Local) { - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1)); - remote_.UpdateCardStats(BuildCard(kCard1, 30, 40, kAddr2)); - - // The billing address from the local version of the card should be kept since - // it refers to a local autofill profile. The highest use stats should - // be kept. - EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches( - kCard1, 30, 40, kLocalAddr1))); - EXPECT_CALL(local_, SendChangesToSyncServer( - UnorderedElementsAre(SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 30, 40, kLocalAddr1Utf8)))); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if both local and server have a different non empty billing -// address id, the one refering to a local profile is always kept. Also makes -// sure that for the rest of the fields the highest values are kept. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - SaveHigherValues_DifferentBillingAddressId_KeepLocalId_Remote) { - local_.UpdateCardStats(BuildCard(kCard1, 30, 40, kAddr2)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1)); - - // The billing address from the remote version of the card should be kept - // since it refers to a local autofill profile. The highest use stats should - // be kept. - EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches( - kCard1, 30, 40, kLocalAddr1))); - EXPECT_CALL(local_, SendChangesToSyncServer( - UnorderedElementsAre(SyncCardChangeAndDataMatch( - syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag, - sync_pb::WalletMetadataSpecifics::CARD, - kCard1Utf8, 30, 40, kLocalAddr1Utf8)))); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if both local and server have a different non empty billing -// address id refering to a Wallet address with the same timestamp, the remote -// one is kept. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DifferentServerBillingAddressId_BothSameTimestamp) { - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr2)); - - // The value from the remote should be kept to promote a stable set of values. - EXPECT_CALL(local_, UpdateCardStats( - AutofillCardMetadataMatches(kCard1, 3, 4, kAddr2))); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if both local and server have a different non empty billing -// address id refering to a local profile with the same timestamp, the remote -// one is kept. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - DifferentLocalBillingAddressId_BothSameTimestamp) { - local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr2)); - - // The value from the remote should be kept to promote a stable set of values. - EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches( - kCard1, 3, 4, kLocalAddr2))); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - MergeMetadata(&local_, &remote_); -} - -// Verify that if the local card has a use_count of one, its use_date is -// replaced even if it is more recent (new cards are created with a use_date set -// to the current time). -TEST_F(AutofillWalletMetadataSyncableServiceTest, NewLocalCard) { - local_.UpdateCardStats(BuildCard(kCard1, 1, 5000, kLocalAddr1)); - remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1)); - - EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches( - kCard1, 3, 4, kLocalAddr1))); - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - MergeMetadata(&local_, &remote_); -} - -// Tests that processing remote changes does not trigger a merge. This is a -// specific test for reflection blocking in notifications. -TEST_F(AutofillWalletMetadataSyncableServiceTest, - RemoteChangesDoNotTriggerMerge) { - // Make the backend broadcast back the notifications it receives - ON_CALL(backend_, NotifyOfMultipleAutofillChanges()) - .WillByDefault( - DoAll(Invoke(&local_, &MockService::AutofillMultipleChangedBySync), - Invoke(&remote_, &MockService::AutofillMultipleChangedBySync))); - - // Get initial data from |remote_| into |local_|. - local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - local_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1)); - remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true)); - remote_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1)); - MergeMetadata(&local_, &remote_); - - // Silently update local card in the DB. - local_.UpdateCardStats(BuildCard(kCard1, 7, 8, kAddr1)); - - // Receive a remote update of the address. - syncer::SyncChangeList changes; - changes.push_back(BuildAddressChange( - syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag, - sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 10, 20, true)); - - // Processing remote change should not trigger a commit of the local change. - EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0); - - local_.ProcessSyncChanges(FROM_HERE, changes); -} - -} // namespace -} // namespace autofill
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn index abd4cf3d..3d47bf3 100644 --- a/components/autofill_assistant/browser/BUILD.gn +++ b/components/autofill_assistant/browser/BUILD.gn
@@ -149,8 +149,15 @@ "user_action.cc", "user_action.h", "viewport_mode.h", - "web_controller.cc", - "web_controller.h", + "web/element_finder.cc", + "web/element_finder.h", + "web/element_position_getter.cc", + "web/element_position_getter.h", + "web/web_controller.cc", + "web/web_controller.h", + "web/web_controller_util.cc", + "web/web_controller_util.h", + "web/web_controller_worker.h", "website_login_fetcher.cc", "website_login_fetcher.h", "website_login_fetcher_impl.cc", @@ -200,8 +207,6 @@ "mock_personal_data_manager.h", "mock_service.cc", "mock_service.h", - "mock_web_controller.cc", - "mock_web_controller.h", "mock_website_login_fetcher.cc", "mock_website_login_fetcher.h", "protocol_utils_unittest.cc", @@ -212,6 +217,8 @@ "selector_unittest.cc", "string_conversions_util_unittest.cc", "trigger_context_unittest.cc", + "web/mock_web_controller.cc", + "web/mock_web_controller.h", ] deps = [
diff --git a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc index 5fdf643..e2ad489 100644 --- a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc +++ b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
@@ -14,7 +14,7 @@ #include "components/autofill/core/browser/data_model/autofill_profile.h" #include "components/autofill_assistant/browser/actions/mock_action_delegate.h" #include "components/autofill_assistant/browser/mock_personal_data_manager.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "testing/gmock/include/gmock/gmock.h" namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc b/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc index ad34182..c6bfd874 100644 --- a/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc +++ b/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc
@@ -11,7 +11,7 @@ #include "base/test/bind_test_util.h" #include "base/test/task_environment.h" #include "components/autofill_assistant/browser/actions/mock_action_delegate.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "testing/gmock/include/gmock/gmock.h" namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/actions/prompt_action_unittest.cc b/components/autofill_assistant/browser/actions/prompt_action_unittest.cc index 7092ee8..009a4513 100644 --- a/components/autofill_assistant/browser/actions/prompt_action_unittest.cc +++ b/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
@@ -12,7 +12,7 @@ #include "base/test/mock_callback.h" #include "base/test/task_environment.h" #include "components/autofill_assistant/browser/actions/mock_action_delegate.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "testing/gmock/include/gmock/gmock.h" namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc b/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc index 152a5b4..15426de0 100644 --- a/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc +++ b/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc
@@ -11,7 +11,7 @@ #include "base/test/gmock_callback_support.h" #include "base/test/mock_callback.h" #include "components/autofill_assistant/browser/actions/mock_action_delegate.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "testing/gmock/include/gmock/gmock.h" namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/batch_element_checker.cc b/components/autofill_assistant/browser/batch_element_checker.cc index 4ead9bf..4cdad7c7 100644 --- a/components/autofill_assistant/browser/batch_element_checker.cc +++ b/components/autofill_assistant/browser/batch_element_checker.cc
@@ -10,7 +10,7 @@ #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" -#include "components/autofill_assistant/browser/web_controller.h" +#include "components/autofill_assistant/browser/web/web_controller.h" namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/batch_element_checker.h b/components/autofill_assistant/browser/batch_element_checker.h index 28eb4a85..9cf89362 100644 --- a/components/autofill_assistant/browser/batch_element_checker.h +++ b/components/autofill_assistant/browser/batch_element_checker.h
@@ -40,7 +40,7 @@ using GetFieldValueCallback = base::OnceCallback<void(bool, const std::string&)>; - // Checks an an element. + // Checks an element. // // New element checks cannot be added once Run has been called. void AddElementCheck(const Selector& selector, ElementCheckCallback callback);
diff --git a/components/autofill_assistant/browser/batch_element_checker_unittest.cc b/components/autofill_assistant/browser/batch_element_checker_unittest.cc index cd86325..37695c2 100644 --- a/components/autofill_assistant/browser/batch_element_checker_unittest.cc +++ b/components/autofill_assistant/browser/batch_element_checker_unittest.cc
@@ -12,7 +12,7 @@ #include "base/test/gmock_callback_support.h" #include "base/test/mock_callback.h" #include "base/test/task_environment.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "testing/gmock/include/gmock/gmock.h" using ::base::test::RunOnceCallback;
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h index f57434b..db85c57b 100644 --- a/components/autofill_assistant/browser/controller.h +++ b/components/autofill_assistant/browser/controller.h
@@ -26,7 +26,7 @@ #include "components/autofill_assistant/browser/trigger_context.h" #include "components/autofill_assistant/browser/ui_delegate.h" #include "components/autofill_assistant/browser/user_action.h" -#include "components/autofill_assistant/browser/web_controller.h" +#include "components/autofill_assistant/browser/web/web_controller.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h"
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc index f971edd..672c941 100644 --- a/components/autofill_assistant/browser/controller_unittest.cc +++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -13,10 +13,9 @@ #include "components/autofill_assistant/browser/features.h" #include "components/autofill_assistant/browser/mock_controller_observer.h" #include "components/autofill_assistant/browser/mock_service.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" #include "components/autofill_assistant/browser/service.h" #include "components/autofill_assistant/browser/trigger_context.h" -#include "content/public/test/browser_task_environment.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "content/public/test/navigation_simulator.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_renderer_host.h"
diff --git a/components/autofill_assistant/browser/element_area.cc b/components/autofill_assistant/browser/element_area.cc index cd9c11a..23ddb00 100644 --- a/components/autofill_assistant/browser/element_area.cc +++ b/components/autofill_assistant/browser/element_area.cc
@@ -12,7 +12,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "components/autofill_assistant/browser/script_executor_delegate.h" -#include "components/autofill_assistant/browser/web_controller.h" +#include "components/autofill_assistant/browser/web/web_controller.h" namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/element_area_unittest.cc b/components/autofill_assistant/browser/element_area_unittest.cc index 946d737..db37aa6 100644 --- a/components/autofill_assistant/browser/element_area_unittest.cc +++ b/components/autofill_assistant/browser/element_area_unittest.cc
@@ -14,8 +14,8 @@ #include "base/test/mock_callback.h" #include "base/test/task_environment.h" #include "components/autofill_assistant/browser/fake_script_executor_delegate.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" #include "components/autofill_assistant/browser/script_executor_delegate.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "testing/gmock/include/gmock/gmock.h" using ::base::test::RunOnceCallback;
diff --git a/components/autofill_assistant/browser/element_precondition_unittest.cc b/components/autofill_assistant/browser/element_precondition_unittest.cc index 5850608..eb00f23c 100644 --- a/components/autofill_assistant/browser/element_precondition_unittest.cc +++ b/components/autofill_assistant/browser/element_precondition_unittest.cc
@@ -12,8 +12,8 @@ #include "base/test/gmock_callback_support.h" #include "base/test/mock_callback.h" #include "components/autofill_assistant/browser/batch_element_checker.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" #include "components/autofill_assistant/browser/service.pb.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/re2/src/re2/re2.h"
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc index 42ac7a47..b079cfbd 100644 --- a/components/autofill_assistant/browser/script_executor.cc +++ b/components/autofill_assistant/browser/script_executor.cc
@@ -23,7 +23,7 @@ #include "components/autofill_assistant/browser/self_delete_full_card_requester.h" #include "components/autofill_assistant/browser/service.h" #include "components/autofill_assistant/browser/trigger_context.h" -#include "components/autofill_assistant/browser/web_controller.h" +#include "components/autofill_assistant/browser/web/web_controller.h" #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h"
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc index c28d545f..f6d73e7 100644 --- a/components/autofill_assistant/browser/script_executor_unittest.cc +++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -14,8 +14,8 @@ #include "components/autofill_assistant/browser/client_memory.h" #include "components/autofill_assistant/browser/fake_script_executor_delegate.h" #include "components/autofill_assistant/browser/mock_service.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" #include "components/autofill_assistant/browser/service.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "testing/gmock/include/gmock/gmock.h" namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/script_precondition.h b/components/autofill_assistant/browser/script_precondition.h index a3fc996..db4502a 100644 --- a/components/autofill_assistant/browser/script_precondition.h +++ b/components/autofill_assistant/browser/script_precondition.h
@@ -16,7 +16,7 @@ #include "base/memory/weak_ptr.h" #include "components/autofill_assistant/browser/element_precondition.h" #include "components/autofill_assistant/browser/service.pb.h" -#include "components/autofill_assistant/browser/web_controller.h" +#include "components/autofill_assistant/browser/web/web_controller.h" namespace re2 { class RE2;
diff --git a/components/autofill_assistant/browser/script_precondition_unittest.cc b/components/autofill_assistant/browser/script_precondition_unittest.cc index 1212019..d4057a1 100644 --- a/components/autofill_assistant/browser/script_precondition_unittest.cc +++ b/components/autofill_assistant/browser/script_precondition_unittest.cc
@@ -11,9 +11,9 @@ #include "base/run_loop.h" #include "base/test/gmock_callback_support.h" #include "components/autofill_assistant/browser/batch_element_checker.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" #include "components/autofill_assistant/browser/service.pb.h" #include "components/autofill_assistant/browser/trigger_context.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/re2/src/re2/re2.h"
diff --git a/components/autofill_assistant/browser/script_tracker_unittest.cc b/components/autofill_assistant/browser/script_tracker_unittest.cc index 19457be..131774ab 100644 --- a/components/autofill_assistant/browser/script_tracker_unittest.cc +++ b/components/autofill_assistant/browser/script_tracker_unittest.cc
@@ -10,10 +10,10 @@ #include "base/test/mock_callback.h" #include "components/autofill_assistant/browser/fake_script_executor_delegate.h" #include "components/autofill_assistant/browser/mock_service.h" -#include "components/autofill_assistant/browser/mock_web_controller.h" #include "components/autofill_assistant/browser/protocol_utils.h" #include "components/autofill_assistant/browser/script_executor_delegate.h" #include "components/autofill_assistant/browser/service.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" #include "testing/gmock/include/gmock/gmock.h" namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/web/element_finder.cc b/components/autofill_assistant/browser/web/element_finder.cc new file mode 100644 index 0000000..41cc5b1f --- /dev/null +++ b/components/autofill_assistant/browser/web/element_finder.cc
@@ -0,0 +1,413 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/web/element_finder.h" + +#include "components/autofill_assistant/browser/devtools/devtools_client.h" +#include "components/autofill_assistant/browser/service.pb.h" +#include "components/autofill_assistant/browser/web/web_controller_util.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" + +namespace autofill_assistant { + +namespace { +// Javascript code to get document root element. +const char* const kGetDocumentElement = + R"( + (function() { + return document.documentElement; + }()) + )"; + +// Javascript code to query an elements for a selector, either the first +// (non-strict) or a single (strict) element. +// +// Returns undefined if no elements are found, TOO_MANY_ELEMENTS (18) if too +// many elements were found and strict mode is enabled. +const char* const kQuerySelector = + R"(function (selector, strictMode) { + var found = this.querySelectorAll(selector); + if(found.length == 0) return undefined; + if(found.length > 1 && strictMode) return 18; + return found[0]; + })"; + +// Javascript code to query a visible elements for a selector, either the first +// (non-strict) or a single (strict) visible element.q +// +// Returns undefined if no elements are found, TOO_MANY_ELEMENTS (18) if too +// many elements were found and strict mode is enabled. +const char* const kQuerySelectorWithConditions = + R"(function (selector, strict, visible, inner_text_str, value_str) { + var found = this.querySelectorAll(selector); + var found_index = -1; + var inner_text_re = inner_text_str ? RegExp(inner_text_str) : undefined; + var value_re = value_str ? RegExp(value_str) : undefined; + var match = function(e) { + if (visible && e.getClientRects().length == 0) return false; + if (inner_text_re && !inner_text_re.test(e.innerText)) return false; + if (value_re && !value_re.test(e.value)) return false; + return true; + }; + for (let i = 0; i < found.length; i++) { + if (match(found[i])) { + if (found_index != -1) return 18; + found_index = i; + if (!strict) break; + } + } + return found_index == -1 ? undefined : found[found_index]; + })"; + +bool ConvertPseudoType(const PseudoType pseudo_type, + dom::PseudoType* pseudo_type_output) { + switch (pseudo_type) { + case PseudoType::UNDEFINED: + break; + case PseudoType::FIRST_LINE: + *pseudo_type_output = dom::PseudoType::FIRST_LINE; + return true; + case PseudoType::FIRST_LETTER: + *pseudo_type_output = dom::PseudoType::FIRST_LETTER; + return true; + case PseudoType::BEFORE: + *pseudo_type_output = dom::PseudoType::BEFORE; + return true; + case PseudoType::AFTER: + *pseudo_type_output = dom::PseudoType::AFTER; + return true; + case PseudoType::BACKDROP: + *pseudo_type_output = dom::PseudoType::BACKDROP; + return true; + case PseudoType::SELECTION: + *pseudo_type_output = dom::PseudoType::SELECTION; + return true; + case PseudoType::FIRST_LINE_INHERITED: + *pseudo_type_output = dom::PseudoType::FIRST_LINE_INHERITED; + return true; + case PseudoType::SCROLLBAR: + *pseudo_type_output = dom::PseudoType::SCROLLBAR; + return true; + case PseudoType::SCROLLBAR_THUMB: + *pseudo_type_output = dom::PseudoType::SCROLLBAR_THUMB; + return true; + case PseudoType::SCROLLBAR_BUTTON: + *pseudo_type_output = dom::PseudoType::SCROLLBAR_BUTTON; + return true; + case PseudoType::SCROLLBAR_TRACK: + *pseudo_type_output = dom::PseudoType::SCROLLBAR_TRACK; + return true; + case PseudoType::SCROLLBAR_TRACK_PIECE: + *pseudo_type_output = dom::PseudoType::SCROLLBAR_TRACK_PIECE; + return true; + case PseudoType::SCROLLBAR_CORNER: + *pseudo_type_output = dom::PseudoType::SCROLLBAR_CORNER; + return true; + case PseudoType::RESIZER: + *pseudo_type_output = dom::PseudoType::RESIZER; + return true; + case PseudoType::INPUT_LIST_BUTTON: + *pseudo_type_output = dom::PseudoType::INPUT_LIST_BUTTON; + return true; + } + return false; +} +} // namespace + +ElementFinder::ElementFinder(content::WebContents* web_contents, + DevtoolsClient* devtools_client, + const Selector& selector, + bool strict) + : web_contents_(web_contents), + devtools_client_(devtools_client), + selector_(selector), + strict_(strict), + element_result_(std::make_unique<Result>()) {} + +ElementFinder::~ElementFinder() = default; + +void ElementFinder::Start(Callback callback) { + callback_ = std::move(callback); + + if (selector_.empty()) { + SendResult(ClientStatus(INVALID_SELECTOR)); + return; + } + devtools_client_->GetRuntime()->Evaluate( + std::string(kGetDocumentElement), + base::BindOnce(&ElementFinder::OnGetDocumentElement, + weak_ptr_factory_.GetWeakPtr())); +} + +void ElementFinder::SendResult(const ClientStatus& status) { + DCHECK(callback_); + DCHECK(element_result_); + std::move(callback_).Run(status, std::move(element_result_)); +} + +void ElementFinder::OnGetDocumentElement( + std::unique_ptr<runtime::EvaluateResult> result) { + ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__); + if (!status.ok()) { + DVLOG(1) << __func__ << " Failed to get document root element."; + SendResult(status); + return; + } + std::string object_id; + if (!SafeGetObjectId(result->GetResult(), &object_id)) { + DVLOG(1) << __func__ << " Failed to get document root element."; + SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED)); + return; + } + element_result_->container_frame_host = web_contents_->GetMainFrame(); + element_result_->container_frame_selector_index = 0; + element_result_->object_id = ""; + RecursiveFindElement(object_id, 0); +} + +void ElementFinder::RecursiveFindElement(const std::string& object_id, + size_t index) { + std::vector<std::unique_ptr<runtime::CallArgument>> argument; + argument.emplace_back(runtime::CallArgument::Builder() + .SetValue(base::Value::ToUniquePtrValue( + base::Value(selector_.selectors[index]))) + .Build()); + // For finding intermediate elements, strict mode would be more appropriate, + // as long as the logic does not support more than one intermediate match. + // + // TODO(b/129387787): first, add logging to figure out whether it matters and + // decide between strict mode and full support for multiple matching + // intermeditate elements. + argument.emplace_back( + runtime::CallArgument::Builder() + .SetValue(base::Value::ToUniquePtrValue(base::Value(strict_))) + .Build()); + std::string function; + if (index == (selector_.selectors.size() - 1)) { + if (selector_.must_be_visible || !selector_.inner_text_pattern.empty() || + !selector_.value_pattern.empty()) { + function.assign(kQuerySelectorWithConditions); + argument.emplace_back(runtime::CallArgument::Builder() + .SetValue(base::Value::ToUniquePtrValue( + base::Value(selector_.must_be_visible))) + .Build()); + argument.emplace_back(runtime::CallArgument::Builder() + .SetValue(base::Value::ToUniquePtrValue( + base::Value(selector_.inner_text_pattern))) + .Build()); + argument.emplace_back(runtime::CallArgument::Builder() + .SetValue(base::Value::ToUniquePtrValue( + base::Value(selector_.value_pattern))) + .Build()); + } + } + if (function.empty()) { + function.assign(kQuerySelector); + } + devtools_client_->GetRuntime()->CallFunctionOn( + runtime::CallFunctionOnParams::Builder() + .SetObjectId(object_id) + .SetArguments(std::move(argument)) + .SetFunctionDeclaration(function) + .Build(), + base::BindOnce(&ElementFinder::OnQuerySelectorAll, + weak_ptr_factory_.GetWeakPtr(), index)); +} + +void ElementFinder::OnQuerySelectorAll( + size_t index, + std::unique_ptr<runtime::CallFunctionOnResult> result) { + if (!result) { + // It is possible for a document element to already exist, but not be + // available yet to query because the document hasn't been loaded. This + // results in OnQuerySelectorAll getting a nullptr result. For this specific + // call, it is expected. + DVLOG(1) << __func__ << ": Context doesn't exist yet to query selector " + << index << " of " << selector_; + SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED)); + return; + } + ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__); + if (!status.ok()) { + DVLOG(1) << __func__ << ": Failed to query selector " << index << " of " + << selector_; + SendResult(status); + return; + } + int int_result; + if (SafeGetIntValue(result->GetResult(), &int_result)) { + DCHECK(int_result == TOO_MANY_ELEMENTS); + SendResult(ClientStatus(TOO_MANY_ELEMENTS)); + return; + } + std::string object_id; + if (!SafeGetObjectId(result->GetResult(), &object_id)) { + SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED)); + return; + } + + if (selector_.selectors.size() == index + 1) { + // The pseudo type is associated to the final element matched by + // |selector_|, which means that we currently don't handle matching an + // element inside a pseudo element. + if (selector_.pseudo_type == PseudoType::UNDEFINED) { + // Return object id of the element. + element_result_->object_id = object_id; + SendResult(OkClientStatus()); + return; + } + + // We are looking for a pseudo element associated with this element. + dom::PseudoType pseudo_type; + if (!ConvertPseudoType(selector_.pseudo_type, &pseudo_type)) { + // Return empty result. + SendResult(ClientStatus(INVALID_ACTION)); + return; + } + + devtools_client_->GetDOM()->DescribeNode( + dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(), + base::BindOnce(&ElementFinder::OnDescribeNodeForPseudoElement, + weak_ptr_factory_.GetWeakPtr(), pseudo_type)); + return; + } + + devtools_client_->GetDOM()->DescribeNode( + dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(), + base::BindOnce(&ElementFinder::OnDescribeNode, + weak_ptr_factory_.GetWeakPtr(), object_id, index)); +} + +void ElementFinder::OnDescribeNodeForPseudoElement( + dom::PseudoType pseudo_type, + std::unique_ptr<dom::DescribeNodeResult> result) { + if (!result || !result->GetNode()) { + DVLOG(1) << __func__ << " Failed to describe the node for pseudo element."; + SendResult(UnexpectedErrorStatus(__FILE__, __LINE__)); + return; + } + + auto* node = result->GetNode(); + if (node->HasPseudoElements()) { + for (const auto& pseudo_element : *(node->GetPseudoElements())) { + if (pseudo_element->HasPseudoType() && + pseudo_element->GetPseudoType() == pseudo_type) { + devtools_client_->GetDOM()->ResolveNode( + dom::ResolveNodeParams::Builder() + .SetBackendNodeId(pseudo_element->GetBackendNodeId()) + .Build(), + base::BindOnce(&ElementFinder::OnResolveNodeForPseudoElement, + weak_ptr_factory_.GetWeakPtr())); + return; + } + } + } + + // Failed to find the pseudo element: run the callback with empty result. + SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED)); +} + +void ElementFinder::OnResolveNodeForPseudoElement( + std::unique_ptr<dom::ResolveNodeResult> result) { + if (result && result->GetObject() && result->GetObject()->HasObjectId()) { + element_result_->object_id = result->GetObject()->GetObjectId(); + } + SendResult(OkClientStatus()); +} + +void ElementFinder::OnDescribeNode( + const std::string& object_id, + size_t index, + std::unique_ptr<dom::DescribeNodeResult> result) { + if (!result || !result->GetNode()) { + DVLOG(1) << __func__ << " Failed to describe the node."; + SendResult(UnexpectedErrorStatus(__FILE__, __LINE__)); + return; + } + + auto* node = result->GetNode(); + std::vector<int> backend_ids; + if (node->HasContentDocument()) { + backend_ids.emplace_back(node->GetContentDocument()->GetBackendNodeId()); + + element_result_->container_frame_selector_index = index; + + // Find out the corresponding render frame host through document url and + // name. + // TODO(crbug.com/806868): Use more attributes to find out the render frame + // host if name and document url are not enough to uniquely identify it. + std::string frame_name; + if (node->HasAttributes()) { + const std::vector<std::string>* attributes = node->GetAttributes(); + for (size_t i = 0; i < attributes->size();) { + if ((*attributes)[i] == "name") { + frame_name = (*attributes)[i + 1]; + break; + } + // Jump two positions since attribute name and value are always paired. + i = i + 2; + } + } + element_result_->container_frame_host = FindCorrespondingRenderFrameHost( + frame_name, node->GetContentDocument()->GetDocumentURL()); + if (!element_result_->container_frame_host) { + DVLOG(1) << __func__ << " Failed to find corresponding owner frame."; + SendResult(UnexpectedErrorStatus(__FILE__, __LINE__)); + return; + } + } else if (node->HasFrameId()) { + // TODO(crbug.com/806868): Support out-of-process iframe. + DVLOG(3) << "Warning (unsupported): the element is inside an OOPIF."; + SendResult(ClientStatus(UNSUPPORTED)); + return; + } + + if (node->HasShadowRoots()) { + // TODO(crbug.com/806868): Support multiple shadow roots. + backend_ids.emplace_back( + node->GetShadowRoots()->front()->GetBackendNodeId()); + } + + if (!backend_ids.empty()) { + devtools_client_->GetDOM()->ResolveNode( + dom::ResolveNodeParams::Builder() + .SetBackendNodeId(backend_ids[0]) + .Build(), + base::BindOnce(&ElementFinder::OnResolveNode, + weak_ptr_factory_.GetWeakPtr(), index)); + return; + } + + RecursiveFindElement(object_id, ++index); +} + +void ElementFinder::OnResolveNode( + size_t index, + std::unique_ptr<dom::ResolveNodeResult> result) { + if (!result || !result->GetObject() || !result->GetObject()->HasObjectId()) { + DVLOG(1) << __func__ << " Failed to resolve object id from backend id."; + SendResult(UnexpectedErrorStatus(__FILE__, __LINE__)); + return; + } + + RecursiveFindElement(result->GetObject()->GetObjectId(), ++index); +} + +content::RenderFrameHost* ElementFinder::FindCorrespondingRenderFrameHost( + std::string name, + std::string document_url) { + content::RenderFrameHost* ret_frame = nullptr; + for (auto* frame : web_contents_->GetAllFrames()) { + if (frame->GetFrameName() == name && + frame->GetLastCommittedURL().spec() == document_url) { + DCHECK(!ret_frame); + ret_frame = frame; + } + } + + return ret_frame; +} + +} // namespace autofill_assistant \ No newline at end of file
diff --git a/components/autofill_assistant/browser/web/element_finder.h b/components/autofill_assistant/browser/web/element_finder.h new file mode 100644 index 0000000..1db746fb --- /dev/null +++ b/components/autofill_assistant/browser/web/element_finder.h
@@ -0,0 +1,95 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_FINDER_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_FINDER_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/autofill_assistant/browser/client_status.h" +#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h" +#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h" +#include "components/autofill_assistant/browser/selector.h" +#include "components/autofill_assistant/browser/web/web_controller_worker.h" + +namespace content { +class WebContents; +class RenderFrameHost; +} // namespace content + +namespace autofill_assistant { +class DevtoolsClient; + +// Worker class to find element(s) matching a selector. +class ElementFinder : public WebControllerWorker { + public: + struct Result { + Result() = default; + ~Result() = default; + + // The render frame host contains the element. + content::RenderFrameHost* container_frame_host; + + // The selector index in the given selectors corresponding to the container + // frame. Zero indicates the element is in main frame or the first element + // is the container frame selector. Compare main frame with the above + // |container_frame_host| to distinguish them. + size_t container_frame_selector_index; + + // The object id of the element. + std::string object_id; + }; + + // |web_contents| and |devtools_client| must be valid for the lifetime of the + // instance. + ElementFinder(content::WebContents* web_contents_, + DevtoolsClient* devtools_client, + const Selector& selector, + bool strict); + ~ElementFinder() override; + + using Callback = + base::OnceCallback<void(const ClientStatus&, std::unique_ptr<Result>)>; + + // Finds the element and calls the callback. + void Start(Callback callback_); + + private: + void SendResult(const ClientStatus& status); + void OnGetDocumentElement(std::unique_ptr<runtime::EvaluateResult> result); + void RecursiveFindElement(const std::string& object_id, size_t index); + void OnQuerySelectorAll( + size_t index, + std::unique_ptr<runtime::CallFunctionOnResult> result); + void OnDescribeNodeForPseudoElement( + dom::PseudoType pseudo_type, + std::unique_ptr<dom::DescribeNodeResult> result); + void OnResolveNodeForPseudoElement( + std::unique_ptr<dom::ResolveNodeResult> result); + void OnDescribeNode(const std::string& object_id, + size_t index, + std::unique_ptr<dom::DescribeNodeResult> result); + void OnResolveNode(size_t index, + std::unique_ptr<dom::ResolveNodeResult> result); + content::RenderFrameHost* FindCorrespondingRenderFrameHost( + std::string name, + std::string document_url); + + content::WebContents* const web_contents_; + DevtoolsClient* const devtools_client_; + const Selector selector_; + const bool strict_; + Callback callback_; + std::unique_ptr<Result> element_result_; + + base::WeakPtrFactory<ElementFinder> weak_ptr_factory_{this}; +}; + +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_FINDER_H_
diff --git a/components/autofill_assistant/browser/web/element_position_getter.cc b/components/autofill_assistant/browser/web/element_position_getter.cc new file mode 100644 index 0000000..8bbbd16 --- /dev/null +++ b/components/autofill_assistant/browser/web/element_position_getter.cc
@@ -0,0 +1,168 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/web/element_position_getter.h" + +#include "base/task/post_task.h" +#include "components/autofill_assistant/browser/devtools/devtools_client.h" +#include "components/autofill_assistant/browser/service.pb.h" +#include "components/autofill_assistant/browser/web/web_controller_util.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/web_contents.h" + +namespace { + +const char* const kScrollIntoViewIfNeededScript = + R"(function(node) { + node.scrollIntoViewIfNeeded(); + })"; + +} // namespace + +namespace autofill_assistant { + +ElementPositionGetter::ElementPositionGetter(DevtoolsClient* devtools_client, + const ClientSettings& settings) + : check_interval_(settings.box_model_check_interval), + max_rounds_(settings.box_model_check_count), + devtools_client_(devtools_client), + weak_ptr_factory_(this) {} + +ElementPositionGetter::~ElementPositionGetter() = default; + +void ElementPositionGetter::Start(content::RenderFrameHost* frame_host, + std::string element_object_id, + ElementPositionCallback callback) { + object_id_ = element_object_id; + callback_ = std::move(callback); + remaining_rounds_ = max_rounds_; + // TODO(crbug/806868): Consider using autofill_assistant::RetryTimer + + // Wait for a roundtrips through the renderer and compositor pipeline, + // otherwise touch event may be dropped because of missing handler. + // Note that mouse left button will always be send to the renderer, but it + // is slightly better to wait for the changes, like scroll, to be visualized + // in compositor as real interaction. + frame_host->InsertVisualStateCallback( + base::BindOnce(&ElementPositionGetter::OnVisualStateUpdatedCallback, + weak_ptr_factory_.GetWeakPtr())); + GetAndWaitBoxModelStable(); +} + +void ElementPositionGetter::OnVisualStateUpdatedCallback(bool success) { + if (success) { + visual_state_updated_ = true; + return; + } + + OnError(); +} + +void ElementPositionGetter::GetAndWaitBoxModelStable() { + devtools_client_->GetDOM()->GetBoxModel( + dom::GetBoxModelParams::Builder().SetObjectId(object_id_).Build(), + base::BindOnce(&ElementPositionGetter::OnGetBoxModelForStableCheck, + weak_ptr_factory_.GetWeakPtr())); +} + +void ElementPositionGetter::OnGetBoxModelForStableCheck( + std::unique_ptr<dom::GetBoxModelResult> result) { + if (!result || !result->GetModel() || !result->GetModel()->GetContent()) { + DVLOG(1) << __func__ << " Failed to get box model."; + OnError(); + return; + } + + // Return the center of the element. + const std::vector<double>* content_box = result->GetModel()->GetContent(); + DCHECK_EQ(content_box->size(), 8u); + int new_point_x = + round((round((*content_box)[0]) + round((*content_box)[2])) * 0.5); + int new_point_y = + round((round((*content_box)[3]) + round((*content_box)[5])) * 0.5); + + // Wait for at least three rounds (~600ms = 3*check_interval_) for visual + // state update callback since it might take longer time to return or never + // return if no updates. + DCHECK(max_rounds_ > 2 && max_rounds_ >= remaining_rounds_); + if (has_point_ && new_point_x == point_x_ && new_point_y == point_y_ && + (visual_state_updated_ || remaining_rounds_ + 2 < max_rounds_)) { + // Note that there is still a chance that the element's position has been + // changed after the last call of GetBoxModel, however, it might be safe to + // assume the element's position will not be changed before issuing click or + // tap event after stable for check_interval_. In addition, checking again + // after issuing click or tap event doesn't help since the change may be + // expected. + OnResult(new_point_x, new_point_y); + return; + } + + if (remaining_rounds_ <= 0) { + OnError(); + return; + } + + bool is_first_round = !has_point_; + has_point_ = true; + point_x_ = new_point_x; + point_y_ = new_point_y; + + // Scroll the element into view again if it was moved out of view, starting + // from the second round. + if (!is_first_round) { + std::vector<std::unique_ptr<runtime::CallArgument>> argument; + argument.emplace_back( + runtime::CallArgument::Builder().SetObjectId(object_id_).Build()); + devtools_client_->GetRuntime()->CallFunctionOn( + runtime::CallFunctionOnParams::Builder() + .SetObjectId(object_id_) + .SetArguments(std::move(argument)) + .SetFunctionDeclaration(std::string(kScrollIntoViewIfNeededScript)) + .SetReturnByValue(true) + .Build(), + base::BindOnce(&ElementPositionGetter::OnScrollIntoView, + weak_ptr_factory_.GetWeakPtr())); + return; + } + + --remaining_rounds_; + base::PostDelayedTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&ElementPositionGetter::GetAndWaitBoxModelStable, + weak_ptr_factory_.GetWeakPtr()), + check_interval_); +} + +void ElementPositionGetter::OnScrollIntoView( + std::unique_ptr<runtime::CallFunctionOnResult> result) { + ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__); + if (!status.ok()) { + DVLOG(1) << __func__ << " Failed to scroll the element: " << status; + OnError(); + return; + } + + --remaining_rounds_; + base::PostDelayedTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&ElementPositionGetter::GetAndWaitBoxModelStable, + weak_ptr_factory_.GetWeakPtr()), + check_interval_); +} + +void ElementPositionGetter::OnResult(int x, int y) { + if (callback_) { + std::move(callback_).Run(/* success= */ true, x, y); + } +} + +void ElementPositionGetter::OnError() { + if (callback_) { + std::move(callback_).Run(/* success= */ false, /* x= */ 0, /* y= */ 0); + } +} + +} // namespace autofill_assistant \ No newline at end of file
diff --git a/components/autofill_assistant/browser/web/element_position_getter.h b/components/autofill_assistant/browser/web/element_position_getter.h new file mode 100644 index 0000000..7a30f6f --- /dev/null +++ b/components/autofill_assistant/browser/web/element_position_getter.h
@@ -0,0 +1,81 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_POSITION_GETTER_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_POSITION_GETTER_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/autofill_assistant/browser/client_settings.h" +#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h" +#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h" +#include "components/autofill_assistant/browser/selector.h" +#include "components/autofill_assistant/browser/web/web_controller_worker.h" + +namespace content { +class RenderFrameHost; +} // namespace content + +namespace autofill_assistant { +class DevtoolsClient; + +// Worker class to get an element's position in viewport coordinates when it is +// stable and the frame it belongs to has finished its visual update. +class ElementPositionGetter : public WebControllerWorker { + public: + // |devtools_client| must be valid for the lifetime of the instance. + ElementPositionGetter(DevtoolsClient* devtools_client, + const ClientSettings& settings); + ~ElementPositionGetter() override; + + // Callback that receives the position that corresponds to the center + // of an element. + // + // If the first element is false, the call failed. Otherwise, the second + // element contains the x position and the third the y position of the center + // of the element in viewport coordinates. + using ElementPositionCallback = base::OnceCallback<void(bool, int, int)>; + + void Start(content::RenderFrameHost* frame_host, + std::string element_object_id, + ElementPositionCallback callback); + + private: + void OnVisualStateUpdatedCallback(bool success); + void GetAndWaitBoxModelStable(); + void OnGetBoxModelForStableCheck( + std::unique_ptr<dom::GetBoxModelResult> result); + void OnScrollIntoView(std::unique_ptr<runtime::CallFunctionOnResult> result); + void OnResult(int x, int y); + void OnError(); + + // Time to wait between two box model checks. + const base::TimeDelta check_interval_; + // Maximum number of checks to run. + const int max_rounds_; + + DevtoolsClient* devtools_client_ = nullptr; + std::string object_id_; + int remaining_rounds_ = 0; + ElementPositionCallback callback_; + bool visual_state_updated_ = false; + + // If |has_point_| is true, |point_x_| and |point_y_| contain the last + // computed center of the element, in viewport coordinates. Note that + // negative coordinates are valid, in case the element is above or to the + // left of the viewport. + bool has_point_ = false; + int point_x_ = 0; + int point_y_ = 0; + + base::WeakPtrFactory<ElementPositionGetter> weak_ptr_factory_; +}; + +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_POSITION_GETTER_H_ \ No newline at end of file
diff --git a/components/autofill_assistant/browser/mock_web_controller.cc b/components/autofill_assistant/browser/web/mock_web_controller.cc similarity index 82% rename from components/autofill_assistant/browser/mock_web_controller.cc rename to components/autofill_assistant/browser/web/mock_web_controller.cc index 21dcf826..b3046aa 100644 --- a/components/autofill_assistant/browser/mock_web_controller.cc +++ b/components/autofill_assistant/browser/web/mock_web_controller.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/autofill_assistant/browser/mock_web_controller.h" +#include "components/autofill_assistant/browser/web/mock_web_controller.h" namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/mock_web_controller.h b/components/autofill_assistant/browser/web/mock_web_controller.h similarity index 92% rename from components/autofill_assistant/browser/mock_web_controller.h rename to components/autofill_assistant/browser/web/mock_web_controller.h index bd2b589e..03e0fb7 100644 --- a/components/autofill_assistant/browser/mock_web_controller.h +++ b/components/autofill_assistant/browser/web/mock_web_controller.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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_WEB_CONTROLLER_H_ -#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_WEB_CONTROLLER_H_ +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_MOCK_WEB_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_MOCK_WEB_CONTROLLER_H_ #include <string> #include <vector> @@ -11,7 +11,7 @@ #include "base/callback.h" #include "components/autofill_assistant/browser/actions/click_action.h" #include "components/autofill_assistant/browser/top_padding.h" -#include "components/autofill_assistant/browser/web_controller.h" +#include "components/autofill_assistant/browser/web/web_controller.h" #include "testing/gmock/include/gmock/gmock.h" namespace autofill_assistant { @@ -119,4 +119,4 @@ } // namespace autofill_assistant -#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_WEB_CONTROLLER_H_ +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_MOCK_WEB_CONTROLLER_H_
diff --git a/components/autofill_assistant/browser/web_controller.cc b/components/autofill_assistant/browser/web/web_controller.cc similarity index 63% rename from components/autofill_assistant/browser/web_controller.cc rename to components/autofill_assistant/browser/web/web_controller.cc index afcf07c..650e84e 100644 --- a/components/autofill_assistant/browser/web_controller.cc +++ b/components/autofill_assistant/browser/web/web_controller.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/autofill_assistant/browser/web_controller.h" +#include "components/autofill_assistant/browser/web/web_controller.h" #include <math.h> #include <algorithm> @@ -13,6 +13,7 @@ #include "base/bind_helpers.h" #include "base/callback.h" #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/strcat.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -27,6 +28,7 @@ #include "components/autofill_assistant/browser/client_status.h" #include "components/autofill_assistant/browser/rectf.h" #include "components/autofill_assistant/browser/string_conversions_util.h" +#include "components/autofill_assistant/browser/web/web_controller_util.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" @@ -75,11 +77,6 @@ node.scrollIntoView({block: "center", inline: "center"}); })"; -const char* const kScrollIntoViewIfNeededScript = - R"(function(node) { - node.scrollIntoViewIfNeeded(); - })"; - // Javascript to select a value from a select box. Also fires a "change" event // to trigger any listeners. Changing the index directly does not trigger this. const char* const kSelectOptionScript = @@ -141,54 +138,6 @@ const char* const kGetOuterHtmlScript = "function () { return this.outerHTML; }"; -// Javascript code to get document root element. -const char* const kGetDocumentElement = - R"( - (function() { - return document.documentElement; - }()) - )"; - -// Javascript code to query an elements for a selector, either the first -// (non-strict) or a single (strict) element. -// -// Returns undefined if no elements are found, TOO_MANY_ELEMENTS (18) if too -// many elements were found and strict mode is enabled. -const char* const kQuerySelector = - R"(function (selector, strictMode) { - var found = this.querySelectorAll(selector); - if(found.length == 0) return undefined; - if(found.length > 1 && strictMode) return 18; - return found[0]; - })"; - -// Javascript code to query a visible elements for a selector, either the first -// (non-strict) or a single (strict) visible element.q -// -// Returns undefined if no elements are found, TOO_MANY_ELEMENTS (18) if too -// many elements were found and strict mode is enabled. -const char* const kQuerySelectorWithConditions = - R"(function (selector, strict, visible, inner_text_str, value_str) { - var found = this.querySelectorAll(selector); - var found_index = -1; - var inner_text_re = inner_text_str ? RegExp(inner_text_str) : undefined; - var value_re = value_str ? RegExp(value_str) : undefined; - var match = function(e) { - if (visible && e.getClientRects().length == 0) return false; - if (inner_text_re && !inner_text_re.test(e.innerText)) return false; - if (value_re && !value_re.test(e.value)) return false; - return true; - }; - for (let i = 0; i < found.length; i++) { - if (match(found[i])) { - if (found_index != -1) return 18; - found_index = i; - if (!strict) break; - } - } - return found_index == -1 ? undefined : found[found_index]; - })"; - // Javascript code to query whether the document is ready for interact. const char* const kIsDocumentReadyForInteract = R"(function () { @@ -222,143 +171,6 @@ }) )"; -bool ConvertPseudoType(const PseudoType pseudo_type, - dom::PseudoType* pseudo_type_output) { - switch (pseudo_type) { - case PseudoType::UNDEFINED: - break; - case PseudoType::FIRST_LINE: - *pseudo_type_output = dom::PseudoType::FIRST_LINE; - return true; - case PseudoType::FIRST_LETTER: - *pseudo_type_output = dom::PseudoType::FIRST_LETTER; - return true; - case PseudoType::BEFORE: - *pseudo_type_output = dom::PseudoType::BEFORE; - return true; - case PseudoType::AFTER: - *pseudo_type_output = dom::PseudoType::AFTER; - return true; - case PseudoType::BACKDROP: - *pseudo_type_output = dom::PseudoType::BACKDROP; - return true; - case PseudoType::SELECTION: - *pseudo_type_output = dom::PseudoType::SELECTION; - return true; - case PseudoType::FIRST_LINE_INHERITED: - *pseudo_type_output = dom::PseudoType::FIRST_LINE_INHERITED; - return true; - case PseudoType::SCROLLBAR: - *pseudo_type_output = dom::PseudoType::SCROLLBAR; - return true; - case PseudoType::SCROLLBAR_THUMB: - *pseudo_type_output = dom::PseudoType::SCROLLBAR_THUMB; - return true; - case PseudoType::SCROLLBAR_BUTTON: - *pseudo_type_output = dom::PseudoType::SCROLLBAR_BUTTON; - return true; - case PseudoType::SCROLLBAR_TRACK: - *pseudo_type_output = dom::PseudoType::SCROLLBAR_TRACK; - return true; - case PseudoType::SCROLLBAR_TRACK_PIECE: - *pseudo_type_output = dom::PseudoType::SCROLLBAR_TRACK_PIECE; - return true; - case PseudoType::SCROLLBAR_CORNER: - *pseudo_type_output = dom::PseudoType::SCROLLBAR_CORNER; - return true; - case PseudoType::RESIZER: - *pseudo_type_output = dom::PseudoType::RESIZER; - return true; - case PseudoType::INPUT_LIST_BUTTON: - *pseudo_type_output = dom::PseudoType::INPUT_LIST_BUTTON; - return true; - } - return false; -} - -// Builds a ClientStatus appropriate for an unexpected error. -// -// This should only be used in situations where getting an error cannot be -// anything but a bug in the client. -ClientStatus UnexpectedErrorStatus(const std::string& file, int line) { - ClientStatus status(OTHER_ACTION_STATUS); - auto* info = status.mutable_details()->mutable_unexpected_error_info(); - info->set_source_file(file); - info->set_source_line_number(line); - return status; -} - -// Builds a ClientStatus appropriate for a JavaScript error. -ClientStatus JavaScriptErrorStatus(const std::string& file, - int line, - const runtime::ExceptionDetails* exception) { - ClientStatus status(UNEXPECTED_JS_ERROR); - auto* info = status.mutable_details()->mutable_unexpected_error_info(); - info->set_source_file(file); - info->set_source_line_number(line); - if (exception) { - if (exception->HasException() && - exception->GetException()->HasClassName()) { - info->set_js_exception_classname( - exception->GetException()->GetClassName()); - } - info->set_js_exception_line_number(exception->GetLineNumber()); - info->set_js_exception_column_number(exception->GetColumnNumber()); - } - return status; -} - -// Makes sure that the given EvaluateResult exists, is successful and contain a -// result. -template <typename T> -ClientStatus CheckJavaScriptResult(T* result, const char* file, int line) { - if (!result) - return JavaScriptErrorStatus(file, line, nullptr); - if (result->HasExceptionDetails()) - return JavaScriptErrorStatus(file, line, result->GetExceptionDetails()); - if (!result->GetResult()) - return JavaScriptErrorStatus(file, line, nullptr); - return OkClientStatus(); -} - -// Safely gets an object id from a RemoteObject -bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out) { - if (result && result->HasObjectId()) { - *out = result->GetObjectId(); - return true; - } - return false; -} - -// Safely gets a string value from a RemoteObject -bool SafeGetStringValue(const runtime::RemoteObject* result, std::string* out) { - if (result && result->HasValue() && result->GetValue()->is_string()) { - *out = result->GetValue()->GetString(); - return true; - } - return false; -} - -// Safely gets a int value from a RemoteObject. -bool SafeGetIntValue(const runtime::RemoteObject* result, int* out) { - if (result && result->HasValue() && result->GetValue()->is_int()) { - *out = result->GetValue()->GetInt(); - return true; - } - *out = 0; - return false; -} - -// Safely gets a boolean value from a RemoteObject -bool SafeGetBool(const runtime::RemoteObject* result, bool* out) { - if (result && result->HasValue() && result->GetValue()->is_bool()) { - *out = result->GetValue()->GetBool(); - return true; - } - *out = false; - return false; -} - // Converts a int that correspond to the DocumentReadyState enum into an // equivalent quoted Javascript string. std::string DocumentReadyStateToQuotedJsString(int state) { @@ -427,548 +239,6 @@ } } // namespace -class WebController::Worker { - public: - Worker(); - virtual ~Worker(); - - private: - DISALLOW_COPY_AND_ASSIGN(Worker); -}; -WebController::Worker::Worker() = default; -WebController::Worker::~Worker() = default; - -class WebController::ElementPositionGetter : public WebController::Worker { - public: - ElementPositionGetter(const ClientSettings& settings); - ~ElementPositionGetter() override; - - // |devtools_client| must be valid for the lifetime of the instance, which is - // guaranteed since workers are owned by WebController. - void Start(content::RenderFrameHost* frame_host, - DevtoolsClient* devtools_client, - std::string element_object_id, - ElementPositionCallback callback); - - private: - void OnVisualStateUpdatedCallback(bool success); - void GetAndWaitBoxModelStable(); - void OnGetBoxModelForStableCheck( - std::unique_ptr<dom::GetBoxModelResult> result); - void OnScrollIntoView(std::unique_ptr<runtime::CallFunctionOnResult> result); - void OnResult(int x, int y); - void OnError(); - - // Time to wait between two box model checks. - const base::TimeDelta check_interval_; - // Maximum number of checks to run. - const int max_rounds_; - - DevtoolsClient* devtools_client_ = nullptr; - std::string object_id_; - int remaining_rounds_ = 0; - ElementPositionCallback callback_; - bool visual_state_updated_ = false; - - // If |has_point_| is true, |point_x_| and |point_y_| contain the last - // computed center of the element, in viewport coordinates. Note that - // negative coordinates are valid, in case the element is above or to the - // left of the viewport. - bool has_point_ = false; - int point_x_ = 0; - int point_y_ = 0; - - base::WeakPtrFactory<ElementPositionGetter> weak_ptr_factory_{this}; -}; - -WebController::ElementPositionGetter::ElementPositionGetter( - const ClientSettings& settings) - : check_interval_(settings.box_model_check_interval), - max_rounds_(settings.box_model_check_count) {} - -WebController::ElementPositionGetter::~ElementPositionGetter() = default; - -void WebController::ElementPositionGetter::Start( - content::RenderFrameHost* frame_host, - DevtoolsClient* devtools_client, - std::string element_object_id, - ElementPositionCallback callback) { - devtools_client_ = devtools_client; - object_id_ = element_object_id; - callback_ = std::move(callback); - remaining_rounds_ = max_rounds_; - // TODO(crbug/806868): Consider using autofill_assistant::RetryTimer - - // Wait for a roundtrips through the renderer and compositor pipeline, - // otherwise touch event may be dropped because of missing handler. - // Note that mouse left button will always be send to the renderer, but it - // is slightly better to wait for the changes, like scroll, to be visualized - // in compositor as real interaction. - frame_host->InsertVisualStateCallback(base::BindOnce( - &WebController::ElementPositionGetter::OnVisualStateUpdatedCallback, - weak_ptr_factory_.GetWeakPtr())); - GetAndWaitBoxModelStable(); -} - -void WebController::ElementPositionGetter::OnVisualStateUpdatedCallback( - bool success) { - if (success) { - visual_state_updated_ = true; - return; - } - - OnError(); -} - -void WebController::ElementPositionGetter::GetAndWaitBoxModelStable() { - devtools_client_->GetDOM()->GetBoxModel( - dom::GetBoxModelParams::Builder().SetObjectId(object_id_).Build(), - base::BindOnce( - &WebController::ElementPositionGetter::OnGetBoxModelForStableCheck, - weak_ptr_factory_.GetWeakPtr())); -} - -void WebController::ElementPositionGetter::OnGetBoxModelForStableCheck( - std::unique_ptr<dom::GetBoxModelResult> result) { - if (!result || !result->GetModel() || !result->GetModel()->GetContent()) { - DVLOG(1) << __func__ << " Failed to get box model."; - OnError(); - return; - } - - // Return the center of the element. - const std::vector<double>* content_box = result->GetModel()->GetContent(); - DCHECK_EQ(content_box->size(), 8u); - int new_point_x = - round((round((*content_box)[0]) + round((*content_box)[2])) * 0.5); - int new_point_y = - round((round((*content_box)[3]) + round((*content_box)[5])) * 0.5); - - // Wait for at least three rounds (~600ms = 3*check_interval_) for visual - // state update callback since it might take longer time to return or never - // return if no updates. - DCHECK(max_rounds_ > 2 && max_rounds_ >= remaining_rounds_); - if (has_point_ && new_point_x == point_x_ && new_point_y == point_y_ && - (visual_state_updated_ || remaining_rounds_ + 2 < max_rounds_)) { - // Note that there is still a chance that the element's position has been - // changed after the last call of GetBoxModel, however, it might be safe to - // assume the element's position will not be changed before issuing click or - // tap event after stable for check_interval_. In addition, checking again - // after issuing click or tap event doesn't help since the change may be - // expected. - OnResult(new_point_x, new_point_y); - return; - } - - if (remaining_rounds_ <= 0) { - OnError(); - return; - } - - bool is_first_round = !has_point_; - has_point_ = true; - point_x_ = new_point_x; - point_y_ = new_point_y; - - // Scroll the element into view again if it was moved out of view, starting - // from the second round. - if (!is_first_round) { - std::vector<std::unique_ptr<runtime::CallArgument>> argument; - argument.emplace_back( - runtime::CallArgument::Builder().SetObjectId(object_id_).Build()); - devtools_client_->GetRuntime()->CallFunctionOn( - runtime::CallFunctionOnParams::Builder() - .SetObjectId(object_id_) - .SetArguments(std::move(argument)) - .SetFunctionDeclaration(std::string(kScrollIntoViewIfNeededScript)) - .SetReturnByValue(true) - .Build(), - base::BindOnce(&WebController::ElementPositionGetter::OnScrollIntoView, - weak_ptr_factory_.GetWeakPtr())); - return; - } - - --remaining_rounds_; - base::PostDelayedTask( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce( - &WebController::ElementPositionGetter::GetAndWaitBoxModelStable, - weak_ptr_factory_.GetWeakPtr()), - check_interval_); -} - -void WebController::ElementPositionGetter::OnScrollIntoView( - std::unique_ptr<runtime::CallFunctionOnResult> result) { - ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__); - if (!status.ok()) { - DVLOG(1) << __func__ << " Failed to scroll the element: " << status; - OnError(); - return; - } - - --remaining_rounds_; - base::PostDelayedTask( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce( - &WebController::ElementPositionGetter::GetAndWaitBoxModelStable, - weak_ptr_factory_.GetWeakPtr()), - check_interval_); -} - -void WebController::ElementPositionGetter::OnResult(int x, int y) { - if (callback_) { - std::move(callback_).Run(/* success= */ true, x, y); - } -} - -void WebController::ElementPositionGetter::OnError() { - if (callback_) { - std::move(callback_).Run(/* success= */ false, /* x= */ 0, /* y= */ 0); - } -} - -class WebController::ElementFinder : public WebController::Worker { - public: - // |devtools_client| and |web_contents| must be valid for the lifetime of the - // instance, which is guaranteed since workers are owned by WebController. - ElementFinder(content::WebContents* web_contents_, - DevtoolsClient* devtools_client, - const Selector& selector, - bool strict); - ~ElementFinder() override; - - // Finds the element and call the callback. - void Start(FindElementCallback callback_); - - private: - void SendResult(const ClientStatus& status); - void OnGetDocumentElement(std::unique_ptr<runtime::EvaluateResult> result); - void RecursiveFindElement(const std::string& object_id, size_t index); - void OnQuerySelectorAll( - size_t index, - std::unique_ptr<runtime::CallFunctionOnResult> result); - void OnDescribeNodeForPseudoElement( - dom::PseudoType pseudo_type, - std::unique_ptr<dom::DescribeNodeResult> result); - void OnResolveNodeForPseudoElement( - std::unique_ptr<dom::ResolveNodeResult> result); - void OnDescribeNode(const std::string& object_id, - size_t index, - std::unique_ptr<dom::DescribeNodeResult> result); - void OnResolveNode(size_t index, - std::unique_ptr<dom::ResolveNodeResult> result); - content::RenderFrameHost* FindCorrespondingRenderFrameHost( - std::string name, - std::string document_url); - - content::WebContents* const web_contents_; - DevtoolsClient* const devtools_client_; - const Selector selector_; - const bool strict_; - FindElementCallback callback_; - std::unique_ptr<FindElementResult> element_result_; - - base::WeakPtrFactory<ElementFinder> weak_ptr_factory_{this}; -}; - -WebController::ElementFinder::ElementFinder(content::WebContents* web_contents, - DevtoolsClient* devtools_client, - const Selector& selector, - bool strict) - : web_contents_(web_contents), - devtools_client_(devtools_client), - selector_(selector), - strict_(strict), - element_result_(std::make_unique<FindElementResult>()) {} - -WebController::ElementFinder::~ElementFinder() = default; - -void WebController::ElementFinder::Start(FindElementCallback callback) { - callback_ = std::move(callback); - - if (selector_.empty()) { - SendResult(ClientStatus(INVALID_SELECTOR)); - return; - } - devtools_client_->GetRuntime()->Evaluate( - std::string(kGetDocumentElement), - base::BindOnce(&WebController::ElementFinder::OnGetDocumentElement, - weak_ptr_factory_.GetWeakPtr())); -} - -void WebController::ElementFinder::SendResult(const ClientStatus& status) { - DCHECK(callback_); - DCHECK(element_result_); - std::move(callback_).Run(status, std::move(element_result_)); -} - -void WebController::ElementFinder::OnGetDocumentElement( - std::unique_ptr<runtime::EvaluateResult> result) { - ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__); - if (!status.ok()) { - DVLOG(1) << __func__ << " Failed to get document root element."; - SendResult(status); - return; - } - std::string object_id; - if (!SafeGetObjectId(result->GetResult(), &object_id)) { - DVLOG(1) << __func__ << " Failed to get document root element."; - SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED)); - return; - } - element_result_->container_frame_host = web_contents_->GetMainFrame(); - element_result_->container_frame_selector_index = 0; - element_result_->object_id = ""; - RecursiveFindElement(object_id, 0); -} - -void WebController::ElementFinder::RecursiveFindElement( - const std::string& object_id, - size_t index) { - std::vector<std::unique_ptr<runtime::CallArgument>> argument; - argument.emplace_back(runtime::CallArgument::Builder() - .SetValue(base::Value::ToUniquePtrValue( - base::Value(selector_.selectors[index]))) - .Build()); - // For finding intermediate elements, strict mode would be more appropriate, - // as long as the logic does not support more than one intermediate match. - // - // TODO(b/129387787): first, add logging to figure out whether it matters and - // decide between strict mode and full support for multiple matching - // intermeditate elements. - argument.emplace_back( - runtime::CallArgument::Builder() - .SetValue(base::Value::ToUniquePtrValue(base::Value(strict_))) - .Build()); - std::string function; - if (index == (selector_.selectors.size() - 1)) { - if (selector_.must_be_visible || !selector_.inner_text_pattern.empty() || - !selector_.value_pattern.empty()) { - function.assign(kQuerySelectorWithConditions); - argument.emplace_back(runtime::CallArgument::Builder() - .SetValue(base::Value::ToUniquePtrValue( - base::Value(selector_.must_be_visible))) - .Build()); - argument.emplace_back(runtime::CallArgument::Builder() - .SetValue(base::Value::ToUniquePtrValue( - base::Value(selector_.inner_text_pattern))) - .Build()); - argument.emplace_back(runtime::CallArgument::Builder() - .SetValue(base::Value::ToUniquePtrValue( - base::Value(selector_.value_pattern))) - .Build()); - } - } - if (function.empty()) { - function.assign(kQuerySelector); - } - devtools_client_->GetRuntime()->CallFunctionOn( - runtime::CallFunctionOnParams::Builder() - .SetObjectId(object_id) - .SetArguments(std::move(argument)) - .SetFunctionDeclaration(function) - .Build(), - base::BindOnce(&WebController::ElementFinder::OnQuerySelectorAll, - weak_ptr_factory_.GetWeakPtr(), index)); -} - -void WebController::ElementFinder::OnQuerySelectorAll( - size_t index, - std::unique_ptr<runtime::CallFunctionOnResult> result) { - if (!result) { - // It is possible for a document element to already exist, but not be - // available yet to query because the document hasn't been loaded. This - // results in OnQuerySelectorAll getting a nullptr result. For this specific - // call, it is expected. - DVLOG(1) << __func__ << ": Context doesn't exist yet to query selector " - << index << " of " << selector_; - SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED)); - return; - } - ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__); - if (!status.ok()) { - DVLOG(1) << __func__ << ": Failed to query selector " << index << " of " - << selector_; - SendResult(status); - return; - } - int int_result; - if (SafeGetIntValue(result->GetResult(), &int_result)) { - DCHECK(int_result == TOO_MANY_ELEMENTS); - SendResult(ClientStatus(TOO_MANY_ELEMENTS)); - return; - } - std::string object_id; - if (!SafeGetObjectId(result->GetResult(), &object_id)) { - SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED)); - return; - } - - if (selector_.selectors.size() == index + 1) { - // The pseudo type is associated to the final element matched by - // |selector_|, which means that we currently don't handle matching an - // element inside a pseudo element. - if (selector_.pseudo_type == PseudoType::UNDEFINED) { - // Return object id of the element. - element_result_->object_id = object_id; - SendResult(OkClientStatus()); - return; - } - - // We are looking for a pseudo element associated with this element. - dom::PseudoType pseudo_type; - if (!ConvertPseudoType(selector_.pseudo_type, &pseudo_type)) { - // Return empty result. - SendResult(ClientStatus(INVALID_ACTION)); - return; - } - - devtools_client_->GetDOM()->DescribeNode( - dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(), - base::BindOnce( - &WebController::ElementFinder::OnDescribeNodeForPseudoElement, - weak_ptr_factory_.GetWeakPtr(), pseudo_type)); - return; - } - - devtools_client_->GetDOM()->DescribeNode( - dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(), - base::BindOnce(&WebController::ElementFinder::OnDescribeNode, - weak_ptr_factory_.GetWeakPtr(), object_id, index)); -} - -void WebController::ElementFinder::OnDescribeNodeForPseudoElement( - dom::PseudoType pseudo_type, - std::unique_ptr<dom::DescribeNodeResult> result) { - if (!result || !result->GetNode()) { - DVLOG(1) << __func__ << " Failed to describe the node for pseudo element."; - SendResult(UnexpectedErrorStatus(__FILE__, __LINE__)); - return; - } - - auto* node = result->GetNode(); - if (node->HasPseudoElements()) { - for (const auto& pseudo_element : *(node->GetPseudoElements())) { - if (pseudo_element->HasPseudoType() && - pseudo_element->GetPseudoType() == pseudo_type) { - devtools_client_->GetDOM()->ResolveNode( - dom::ResolveNodeParams::Builder() - .SetBackendNodeId(pseudo_element->GetBackendNodeId()) - .Build(), - base::BindOnce( - &WebController::ElementFinder::OnResolveNodeForPseudoElement, - weak_ptr_factory_.GetWeakPtr())); - return; - } - } - } - - // Failed to find the pseudo element: run the callback with empty result. - SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED)); -} - -void WebController::ElementFinder::OnResolveNodeForPseudoElement( - std::unique_ptr<dom::ResolveNodeResult> result) { - if (result && result->GetObject() && result->GetObject()->HasObjectId()) { - element_result_->object_id = result->GetObject()->GetObjectId(); - } - SendResult(OkClientStatus()); -} - -void WebController::ElementFinder::OnDescribeNode( - const std::string& object_id, - size_t index, - std::unique_ptr<dom::DescribeNodeResult> result) { - if (!result || !result->GetNode()) { - DVLOG(1) << __func__ << " Failed to describe the node."; - SendResult(UnexpectedErrorStatus(__FILE__, __LINE__)); - return; - } - - auto* node = result->GetNode(); - std::vector<int> backend_ids; - if (node->HasContentDocument()) { - backend_ids.emplace_back(node->GetContentDocument()->GetBackendNodeId()); - - element_result_->container_frame_selector_index = index; - - // Find out the corresponding render frame host through document url and - // name. - // TODO(crbug.com/806868): Use more attributes to find out the render frame - // host if name and document url are not enough to uniquely identify it. - std::string frame_name; - if (node->HasAttributes()) { - const std::vector<std::string>* attributes = node->GetAttributes(); - for (size_t i = 0; i < attributes->size();) { - if ((*attributes)[i] == "name") { - frame_name = (*attributes)[i + 1]; - break; - } - // Jump two positions since attribute name and value are always paired. - i = i + 2; - } - } - element_result_->container_frame_host = FindCorrespondingRenderFrameHost( - frame_name, node->GetContentDocument()->GetDocumentURL()); - if (!element_result_->container_frame_host) { - DVLOG(1) << __func__ << " Failed to find corresponding owner frame."; - SendResult(UnexpectedErrorStatus(__FILE__, __LINE__)); - return; - } - } else if (node->HasFrameId()) { - // TODO(crbug.com/806868): Support out-of-process iframe. - DVLOG(3) << "Warning (unsupported): the element is inside an OOPIF."; - SendResult(ClientStatus(UNSUPPORTED)); - return; - } - - if (node->HasShadowRoots()) { - // TODO(crbug.com/806868): Support multiple shadow roots. - backend_ids.emplace_back( - node->GetShadowRoots()->front()->GetBackendNodeId()); - } - - if (!backend_ids.empty()) { - devtools_client_->GetDOM()->ResolveNode( - dom::ResolveNodeParams::Builder() - .SetBackendNodeId(backend_ids[0]) - .Build(), - base::BindOnce(&WebController::ElementFinder::OnResolveNode, - weak_ptr_factory_.GetWeakPtr(), index)); - return; - } - - RecursiveFindElement(object_id, ++index); -} - -void WebController::ElementFinder::OnResolveNode( - size_t index, - std::unique_ptr<dom::ResolveNodeResult> result) { - if (!result || !result->GetObject() || !result->GetObject()->HasObjectId()) { - DVLOG(1) << __func__ << " Failed to resolve object id from backend id."; - SendResult(UnexpectedErrorStatus(__FILE__, __LINE__)); - return; - } - - RecursiveFindElement(result->GetObject()->GetObjectId(), ++index); -} - -content::RenderFrameHost* -WebController::ElementFinder::FindCorrespondingRenderFrameHost( - std::string name, - std::string document_url) { - content::RenderFrameHost* ret_frame = nullptr; - for (auto* frame : web_contents_->GetAllFrames()) { - if (frame->GetFrameName() == name && - frame->GetLastCommittedURL().spec() == document_url) { - DCHECK(!ret_frame); - ret_frame = frame; - } - } - - return ret_frame; -} - // static std::unique_ptr<WebController> WebController::CreateForWebContents( content::WebContents* web_contents, @@ -1016,7 +286,7 @@ base::OnceCallback<void(const ClientStatus&)> callback, ClickAction::ClickType click_type, const ClientStatus& status, - std::unique_ptr<FindElementResult> result) { + std::unique_ptr<ElementFinder::Result> result) { // Found element must belong to a frame. if (!status.ok()) { DVLOG(1) << __func__ << " Failed to find the element to click or tap."; @@ -1036,7 +306,7 @@ void WebController::OnWaitDocumentToBecomeInteractiveForClickOrTap( base::OnceCallback<void(const ClientStatus&)> callback, ClickAction::ClickType click_type, - std::unique_ptr<FindElementResult> target_element, + std::unique_ptr<ElementFinder::Result> target_element, bool result) { if (!result) { std::move(callback).Run(ClientStatus(TIMED_OUT)); @@ -1047,7 +317,7 @@ } void WebController::ClickOrTapElement( - std::unique_ptr<FindElementResult> target_element, + std::unique_ptr<ElementFinder::Result> target_element, ClickAction::ClickType click_type, base::OnceCallback<void(const ClientStatus&)> callback) { std::string element_object_id = target_element->object_id; @@ -1067,7 +337,7 @@ } void WebController::OnScrollIntoView( - std::unique_ptr<FindElementResult> target_element, + std::unique_ptr<ElementFinder::Result> target_element, base::OnceCallback<void(const ClientStatus&)> callback, ClickAction::ClickType click_type, std::unique_ptr<runtime::CallFunctionOnResult> result) { @@ -1096,15 +366,14 @@ } std::unique_ptr<ElementPositionGetter> getter = - std::make_unique<ElementPositionGetter>(*settings_); - ElementPositionGetter* getter_ptr = getter.get(); - pending_workers_[getter_ptr] = std::move(getter); - getter_ptr->Start(target_element->container_frame_host, - devtools_client_.get(), target_element->object_id, - base::BindOnce(&WebController::TapOrClickOnCoordinates, - weak_ptr_factory_.GetWeakPtr(), - base::Unretained(getter_ptr), - std::move(callback), click_type)); + std::make_unique<ElementPositionGetter>(devtools_client_.get(), + *settings_); + auto* ptr = getter.get(); + pending_workers_.emplace_back(std::move(getter)); + ptr->Start(target_element->container_frame_host, target_element->object_id, + base::BindOnce(&WebController::TapOrClickOnCoordinates, + weak_ptr_factory_.GetWeakPtr(), ptr, + std::move(callback), click_type)); } void WebController::OnClickJS( @@ -1124,7 +393,9 @@ bool has_coordinates, int x, int y) { - pending_workers_.erase(getter_to_release); + base::EraseIf(pending_workers_, [getter_to_release](const auto& worker) { + return worker.get() == getter_to_release; + }); if (!has_coordinates) { DVLOG(1) << __func__ << " Failed to get element position."; @@ -1231,7 +502,7 @@ void WebController::OnFindElementForCheck( base::OnceCallback<void(bool)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> result) { + std::unique_ptr<ElementFinder::Result> result) { DVLOG_IF(1, !status.ok() && status.proto_status() != ELEMENT_RESOLUTION_FAILED) << __func__ << ": " << status; @@ -1296,7 +567,7 @@ DocumentReadyState min_ready_state, base::OnceCallback<void(const ClientStatus&, DocumentReadyState)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element) { + std::unique_ptr<ElementFinder::Result> element) { if (!status.ok()) { std::move(callback).Run(status, DOCUMENT_UNKNOWN_READY_STATE); return; @@ -1326,21 +597,23 @@ void WebController::FindElement(const Selector& selector, bool strict_mode, - FindElementCallback callback) { + ElementFinder::Callback callback) { auto finder = std::make_unique<ElementFinder>( web_contents_, devtools_client_.get(), selector, strict_mode); - ElementFinder* ptr = finder.get(); - pending_workers_[ptr] = std::move(finder); + auto* ptr = finder.get(); + pending_workers_.emplace_back(std::move(finder)); ptr->Start(base::BindOnce(&WebController::OnFindElementResult, base::Unretained(this), ptr, std::move(callback))); } void WebController::OnFindElementResult( ElementFinder* finder_to_release, - FindElementCallback callback, + ElementFinder::Callback callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> result) { - pending_workers_.erase(finder_to_release); + std::unique_ptr<ElementFinder::Result> result) { + base::EraseIf(pending_workers_, [finder_to_release](const auto& worker) { + return worker.get() == finder_to_release; + }); std::move(callback).Run(status, std::move(result)); } @@ -1348,7 +621,7 @@ const TopPadding& top_padding, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result) { + std::unique_ptr<ElementFinder::Result> element_result) { if (!status.ok()) { DVLOG(1) << __func__ << " Failed to find the element to focus on."; std::move(callback).Run(status); @@ -1367,7 +640,7 @@ void WebController::OnWaitDocumentToBecomeInteractiveForFocusElement( const TopPadding& top_padding, base::OnceCallback<void(const ClientStatus&)> callback, - std::unique_ptr<FindElementResult> target_element, + std::unique_ptr<ElementFinder::Result> target_element, bool result) { if (!result) { std::move(callback).Run(ClientStatus(ELEMENT_UNSTABLE)); @@ -1426,7 +699,7 @@ const Selector& selector, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result) { + std::unique_ptr<ElementFinder::Result> element_result) { if (!status.ok()) { DVLOG(1) << __func__ << " Failed to find the element for filling the form."; std::move(callback).Run(status); @@ -1514,7 +787,7 @@ const std::string& selected_option, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result) { + std::unique_ptr<ElementFinder::Result> element_result) { if (!status.ok()) { DVLOG(1) << __func__ << " Failed to find the element to select an option."; std::move(callback).Run(status); @@ -1573,7 +846,7 @@ void WebController::OnFindElementForHighlightElement( base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result) { + std::unique_ptr<ElementFinder::Result> element_result) { if (!status.ok()) { DVLOG(1) << __func__ << " Failed to find the element to highlight."; std::move(callback).Run(status); @@ -1629,7 +902,7 @@ void WebController::OnFindElementForGetFieldValue( base::OnceCallback<void(bool, const std::string&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result) { + std::unique_ptr<ElementFinder::Result> element_result) { const std::string object_id = element_result->object_id; if (!status.ok()) { std::move(callback).Run(/* exists= */ false, ""); @@ -1794,7 +1067,7 @@ const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result) { + std::unique_ptr<ElementFinder::Result> element_result) { if (!status.ok()) { std::move(callback).Run(status); return; @@ -1844,7 +1117,7 @@ const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result) { + std::unique_ptr<ElementFinder::Result> element_result) { if (!status.ok()) { std::move(callback).Run(status); return; @@ -1909,7 +1182,7 @@ const int delay_in_millisecond, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result) { + std::unique_ptr<ElementFinder::Result> element_result) { if (!status.ok()) { std::move(callback).Run(status); return; @@ -1986,7 +1259,7 @@ void WebController::OnFindElementForPosition( base::OnceCallback<void(bool, const RectF&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> result) { + std::unique_ptr<ElementFinder::Result> result) { if (!status.ok()) { RectF empty; std::move(callback).Run(false, empty); @@ -2035,7 +1308,7 @@ void WebController::OnFindElementForGetOuterHtml( base::OnceCallback<void(const ClientStatus&, const std::string&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result) { + std::unique_ptr<ElementFinder::Result> element_result) { if (!status.ok()) { DVLOG(2) << __func__ << " Failed to find element for GetOuterHtml"; std::move(callback).Run(status, "");
diff --git a/components/autofill_assistant/browser/web_controller.h b/components/autofill_assistant/browser/web/web_controller.h similarity index 83% rename from components/autofill_assistant/browser/web_controller.h rename to components/autofill_assistant/browser/web/web_controller.h index bccb40c..46d1bea 100644 --- a/components/autofill_assistant/browser/web_controller.h +++ b/components/autofill_assistant/browser/web/web_controller.h
@@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CONTROLLER_H_ -#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CONTROLLER_H_ +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_H_ -#include <map> #include <memory> #include <string> #include <vector> @@ -24,6 +23,9 @@ #include "components/autofill_assistant/browser/rectf.h" #include "components/autofill_assistant/browser/selector.h" #include "components/autofill_assistant/browser/top_padding.h" +#include "components/autofill_assistant/browser/web/element_finder.h" +#include "components/autofill_assistant/browser/web/element_position_getter.h" +#include "components/autofill_assistant/browser/web/web_controller_worker.h" #include "third_party/icu/source/common/unicode/umachine.h" #include "url/gurl.h" @@ -40,7 +42,7 @@ namespace autofill { struct FormData; struct FormFieldData; -} +} // namespace autofill namespace autofill_assistant { struct ClientSettings; @@ -204,47 +206,6 @@ private: friend class WebControllerBrowserTest; - // Callback that receives the position that corresponds to the center - // of an element, from ElementPositionGetter. - // - // If the first element is false, the call failed. Otherwise, the second - // element contains the x position and the third the y position of the center - // of the element in viewport coordinates. - using ElementPositionCallback = base::OnceCallback<void(bool, int, int)>; - - // Superclass for workers that execute complex operation and keep a pointer to - // this controller or the devtools client. Workers are owned by - // pending_workers_ and are removed once the operation is finished. - class Worker; - - // Worker class to get element's position in viewport coordinates when is - // stable and the frame it belongs finished visual update. - class ElementPositionGetter; - - // Worker class to find element(s) matching a selector. Returns - // FindElementResult. - class ElementFinder; - - struct FindElementResult { - FindElementResult() = default; - ~FindElementResult() = default; - - // The render frame host contains the element. - content::RenderFrameHost* container_frame_host; - - // The selector index in the given selectors corresponding to the container - // frame. Zero indicates the element is in main frame or the first element - // is the container frame selector. Compare main frame with the above - // |container_frame_host| to distinguish them. - size_t container_frame_selector_index; - - // The object id of the element. - std::string object_id; - }; - using FindElementCallback = - base::OnceCallback<void(const ClientStatus&, - std::unique_ptr<FindElementResult>)>; - struct FillFormInputData { FillFormInputData(); ~FillFormInputData(); @@ -261,23 +222,23 @@ base::OnceCallback<void(const ClientStatus&)> callback, ClickAction::ClickType click_type, const ClientStatus& status, - std::unique_ptr<FindElementResult> result); + std::unique_ptr<ElementFinder::Result> result); void OnWaitDocumentToBecomeInteractiveForClickOrTap( base::OnceCallback<void(const ClientStatus&)> callback, ClickAction::ClickType click_type, - std::unique_ptr<FindElementResult> target_element, + std::unique_ptr<ElementFinder::Result> target_element, bool result); void OnFindElementForTap( base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> result); + std::unique_ptr<ElementFinder::Result> result); void ClickOrTapElement( - std::unique_ptr<FindElementResult> target_element, + std::unique_ptr<ElementFinder::Result> target_element, ClickAction::ClickType click_type, base::OnceCallback<void(const ClientStatus&)> callback); void OnClickJS(base::OnceCallback<void(const ClientStatus&)> callback, std::unique_ptr<runtime::CallFunctionOnResult> result); - void OnScrollIntoView(std::unique_ptr<FindElementResult> target_element, + void OnScrollIntoView(std::unique_ptr<ElementFinder::Result> target_element, base::OnceCallback<void(const ClientStatus&)> callback, ClickAction::ClickType click_type, std::unique_ptr<runtime::CallFunctionOnResult> result); @@ -304,7 +265,7 @@ std::unique_ptr<input::DispatchTouchEventResult> result); void OnFindElementForCheck(base::OnceCallback<void(bool)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> result); + std::unique_ptr<ElementFinder::Result> result); void OnWaitForWindowHeightChange( base::OnceCallback<void(const ClientStatus&)> callback, std::unique_ptr<runtime::EvaluateResult> result); @@ -314,17 +275,17 @@ // found. Otherwise if |strict-mode| is true, do not return any. void FindElement(const Selector& selector, bool strict_mode, - FindElementCallback callback); + ElementFinder::Callback callback); void OnFindElementResult(ElementFinder* finder_to_release, - FindElementCallback callback, + ElementFinder::Callback callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> result); + std::unique_ptr<ElementFinder::Result> result); void OnFindElementForFillingForm( std::unique_ptr<FillFormInputData> data_to_autofill, const Selector& selector, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result); + std::unique_ptr<ElementFinder::Result> element_result); void OnGetFormAndFieldDataForFillingForm( std::unique_ptr<FillFormInputData> data_to_autofill, base::OnceCallback<void(const ClientStatus&)> callback, @@ -335,11 +296,11 @@ const TopPadding& top_padding, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result); + std::unique_ptr<ElementFinder::Result> element_result); void OnWaitDocumentToBecomeInteractiveForFocusElement( const TopPadding& top_padding, base::OnceCallback<void(const ClientStatus&)> callback, - std::unique_ptr<FindElementResult> target_element, + std::unique_ptr<ElementFinder::Result> target_element, bool result); void OnFocusElement(base::OnceCallback<void(const ClientStatus&)> callback, std::unique_ptr<runtime::CallFunctionOnResult> result); @@ -347,20 +308,20 @@ const std::string& selected_option, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result); + std::unique_ptr<ElementFinder::Result> element_result); void OnSelectOption(base::OnceCallback<void(const ClientStatus&)> callback, std::unique_ptr<runtime::CallFunctionOnResult> result); void OnFindElementForHighlightElement( base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result); + std::unique_ptr<ElementFinder::Result> element_result); void OnHighlightElement( base::OnceCallback<void(const ClientStatus&)> callback, std::unique_ptr<runtime::CallFunctionOnResult> result); void OnFindElementForGetFieldValue( base::OnceCallback<void(bool, const std::string&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result); + std::unique_ptr<ElementFinder::Result> element_result); void OnGetValueAttribute( base::OnceCallback<void(bool, const std::string&)> callback, std::unique_ptr<runtime::CallFunctionOnResult> result); @@ -395,7 +356,7 @@ const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result); + std::unique_ptr<ElementFinder::Result> element_result); void OnSetAttribute(base::OnceCallback<void(const ClientStatus&)> callback, std::unique_ptr<runtime::CallFunctionOnResult> result); void OnFindElementForSendKeyboardInput( @@ -404,12 +365,12 @@ int delay_in_milli, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result); + std::unique_ptr<ElementFinder::Result> element_result); void OnFindElementForSetFieldValue( const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result); + std::unique_ptr<ElementFinder::Result> element_result); void OnSetValueAttribute( base::OnceCallback<void(const ClientStatus&)> callback, std::unique_ptr<runtime::CallFunctionOnResult> result); @@ -417,14 +378,14 @@ base::OnceCallback<void(const ClientStatus&, const std::string&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element_result); + std::unique_ptr<ElementFinder::Result> element_result); void OnGetOuterHtml(base::OnceCallback<void(const ClientStatus&, const std::string&)> callback, std::unique_ptr<runtime::CallFunctionOnResult> result); void OnFindElementForPosition( base::OnceCallback<void(bool, const RectF&)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> result); + std::unique_ptr<ElementFinder::Result> result); void OnGetVisualViewport( base::OnceCallback<void(bool, const RectF&)> callback, std::unique_ptr<runtime::EvaluateResult> result); @@ -450,17 +411,12 @@ std::string object_id, base::OnceCallback<void(bool)> callback, std::unique_ptr<runtime::CallFunctionOnResult> result); - void OnFindElementForDocumentReadyState( - base::OnceCallback<void(const ClientStatus&, const std::string&)> - callback, - const ClientStatus& status, - std::unique_ptr<FindElementResult> element); void OnFindElementForWaitForDocumentReadyState( DocumentReadyState min_ready_state, base::OnceCallback<void(const ClientStatus&, DocumentReadyState)> callback, const ClientStatus& status, - std::unique_ptr<FindElementResult> element); + std::unique_ptr<ElementFinder::Result> element); // Weak pointer is fine here since it must outlive this web controller, which // is guaranteed by the owner of this object. @@ -468,11 +424,11 @@ std::unique_ptr<DevtoolsClient> devtools_client_; const ClientSettings* const settings_; - // Workers currently running and using |devtools_client_|. - std::map<Worker*, std::unique_ptr<Worker>> pending_workers_; + // Currently running workers. + std::vector<std::unique_ptr<WebControllerWorker>> pending_workers_; base::WeakPtrFactory<WebController> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(WebController); }; } // namespace autofill_assistant -#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CONTROLLER_H_ +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_H_
diff --git a/components/autofill_assistant/browser/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc similarity index 98% rename from components/autofill_assistant/browser/web_controller_browsertest.cc rename to components/autofill_assistant/browser/web/web_controller_browsertest.cc index 47b497d..9481f48 100644 --- a/components/autofill_assistant/browser/web_controller_browsertest.cc +++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -10,7 +10,7 @@ #include "components/autofill_assistant/browser/service.pb.h" #include "components/autofill_assistant/browser/string_conversions_util.h" #include "components/autofill_assistant/browser/top_padding.h" -#include "components/autofill_assistant/browser/web_controller.h" +#include "components/autofill_assistant/browser/web/web_controller.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" @@ -238,7 +238,7 @@ void FindElement(const Selector& selector, ClientStatus* status_out, - WebController::FindElementResult* result_out) { + ElementFinder::Result* result_out) { base::RunLoop run_loop; web_controller_->FindElement( selector, /* strict_mode= */ true, @@ -251,9 +251,9 @@ void OnFindElement(const base::Closure& done_callback, ClientStatus* status_out, - WebController::FindElementResult* result_out, + ElementFinder::Result* result_out, const ClientStatus& status, - std::unique_ptr<WebController::FindElementResult> result) { + std::unique_ptr<ElementFinder::Result> result) { ASSERT_TRUE(result); done_callback.Run(); if (status_out) @@ -268,7 +268,7 @@ bool is_main_frame) { SCOPED_TRACE(::testing::Message() << selector << " strict"); ClientStatus status; - WebController::FindElementResult result; + ElementFinder::Result result; FindElement(selector, &status, &result); EXPECT_EQ(ACTION_APPLIED, status.proto_status()); CheckFindElementResult(result, expected_index, is_main_frame); @@ -277,13 +277,13 @@ void FindElementExpectEmptyResult(const Selector& selector) { SCOPED_TRACE(::testing::Message() << selector << " strict"); ClientStatus status; - WebController::FindElementResult result; + ElementFinder::Result result; FindElement(selector, &status, &result); EXPECT_EQ(ELEMENT_RESOLUTION_FAILED, status.proto_status()); EXPECT_THAT(result.object_id, IsEmpty()); } - void CheckFindElementResult(const WebController::FindElementResult& result, + void CheckFindElementResult(const ElementFinder::Result& result, size_t expected_index, bool is_main_frame) { if (is_main_frame) { @@ -677,8 +677,7 @@ WaitForElementRemove(selector); } -IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, - ClickElementInIFrame) { +IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ClickElementInIFrame) { Selector selector; selector.selectors.emplace_back("#iframe"); selector.selectors.emplace_back("#shadowsection"); @@ -1241,4 +1240,4 @@ AnyOf(DOCUMENT_LOADED, DOCUMENT_INTERACTIVE, DOCUMENT_COMPLETE)); } -} // namespace +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web/web_controller_util.cc b/components/autofill_assistant/browser/web/web_controller_util.cc new file mode 100644 index 0000000..8ca38eeb --- /dev/null +++ b/components/autofill_assistant/browser/web/web_controller_util.cc
@@ -0,0 +1,70 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/web/web_controller_util.h" + +namespace autofill_assistant { + +ClientStatus UnexpectedErrorStatus(const std::string& file, int line) { + ClientStatus status(OTHER_ACTION_STATUS); + auto* info = status.mutable_details()->mutable_unexpected_error_info(); + info->set_source_file(file); + info->set_source_line_number(line); + return status; +} + +ClientStatus JavaScriptErrorStatus(const std::string& file, + int line, + const runtime::ExceptionDetails* exception) { + ClientStatus status(UNEXPECTED_JS_ERROR); + auto* info = status.mutable_details()->mutable_unexpected_error_info(); + info->set_source_file(file); + info->set_source_line_number(line); + if (exception) { + if (exception->HasException() && + exception->GetException()->HasClassName()) { + info->set_js_exception_classname( + exception->GetException()->GetClassName()); + } + info->set_js_exception_line_number(exception->GetLineNumber()); + info->set_js_exception_column_number(exception->GetColumnNumber()); + } + return status; +} + +bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out) { + if (result && result->HasObjectId()) { + *out = result->GetObjectId(); + return true; + } + return false; +} + +bool SafeGetStringValue(const runtime::RemoteObject* result, std::string* out) { + if (result && result->HasValue() && result->GetValue()->is_string()) { + *out = result->GetValue()->GetString(); + return true; + } + return false; +} + +bool SafeGetIntValue(const runtime::RemoteObject* result, int* out) { + if (result && result->HasValue() && result->GetValue()->is_int()) { + *out = result->GetValue()->GetInt(); + return true; + } + *out = 0; + return false; +} + +bool SafeGetBool(const runtime::RemoteObject* result, bool* out) { + if (result && result->HasValue() && result->GetValue()->is_bool()) { + *out = result->GetValue()->GetBool(); + return true; + } + *out = false; + return false; +} + +} // namespace autofill_assistant \ No newline at end of file
diff --git a/components/autofill_assistant/browser/web/web_controller_util.h b/components/autofill_assistant/browser/web/web_controller_util.h new file mode 100644 index 0000000..79c618c --- /dev/null +++ b/components/autofill_assistant/browser/web/web_controller_util.h
@@ -0,0 +1,52 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_UTIL_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_UTIL_H_ + +#include <string> +#include "components/autofill_assistant/browser/client_status.h" +#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h" + +namespace autofill_assistant { + +// Builds a ClientStatus appropriate for an unexpected error. +// +// This should only be used in situations where getting an error cannot be +// anything but a bug in the client. +ClientStatus UnexpectedErrorStatus(const std::string& file, int line); + +// Builds a ClientStatus appropriate for a JavaScript error. +ClientStatus JavaScriptErrorStatus(const std::string& file, + int line, + const runtime::ExceptionDetails* exception); + +// Makes sure that the given EvaluateResult exists, is successful and contains a +// result. +template <typename T> +ClientStatus CheckJavaScriptResult(T* result, const char* file, int line) { + if (!result) + return JavaScriptErrorStatus(file, line, nullptr); + if (result->HasExceptionDetails()) + return JavaScriptErrorStatus(file, line, result->GetExceptionDetails()); + if (!result->GetResult()) + return JavaScriptErrorStatus(file, line, nullptr); + return OkClientStatus(); +} + +// Safely gets an object id from a RemoteObject +bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out); + +// Safely gets a string value from a RemoteObject +bool SafeGetStringValue(const runtime::RemoteObject* result, std::string* out); + +// Safely gets a int value from a RemoteObject. +bool SafeGetIntValue(const runtime::RemoteObject* result, int* out); + +// Safely gets a boolean value from a RemoteObject +bool SafeGetBool(const runtime::RemoteObject* result, bool* out); + +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_UTIL_H_ \ No newline at end of file
diff --git a/components/autofill_assistant/browser/web/web_controller_worker.h b/components/autofill_assistant/browser/web/web_controller_worker.h new file mode 100644 index 0000000..5da5a27 --- /dev/null +++ b/components/autofill_assistant/browser/web/web_controller_worker.h
@@ -0,0 +1,27 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_WORKER_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_WORKER_H_ + +#include "base/macros.h" + +namespace autofill_assistant { + +// Superclass for workers of |WebController| that execute complex operations. +// This superclass merely ensures that workers can be memory-managed by +// others (in particular an instance of |WebController|), by making the +// base constructor/destructor public. +class WebControllerWorker { + public: + WebControllerWorker() = default; + virtual ~WebControllerWorker() = default; + + private: + DISALLOW_COPY_AND_ASSIGN(WebControllerWorker); +}; + +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_WORKER_H_ \ No newline at end of file
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java index 77c55d6..74a432b 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java
@@ -177,6 +177,12 @@ builder.setExtras(mTaskExtras); mBuilder = builder; } + + @Override + public void visit(TaskInfo.ExactInfo exactInfo) { + throw new RuntimeException("Exact tasks should not be scheduled with " + + "GcmNetworkManager."); + } } private static int getGcmNetworkManagerNetworkTypeFromTypeFromTaskNetworkType(
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java index 1bb91a9..99762bbc 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java
@@ -48,9 +48,8 @@ taskInfo.getTaskId(), success); // Retain expiration metrics - ExpirationMetricsVisitor expirationMetricsVisitor = - new ExpirationMetricsVisitor(taskInfo.getTaskId()); - taskInfo.getTimingInfo().accept(expirationMetricsVisitor); + MetricsVisitor metricsVisitor = new MetricsVisitor(taskInfo.getTaskId()); + taskInfo.getTimingInfo().accept(metricsVisitor); if (success) { BackgroundTaskSchedulerPrefs.addScheduledTask(taskInfo); @@ -60,10 +59,10 @@ } // TODO(crbug.com/996178): Update the documentation for the expiration feature. - private class ExpirationMetricsVisitor implements TaskInfo.TimingInfoVisitor { + private class MetricsVisitor implements TaskInfo.TimingInfoVisitor { private final int mTaskId; - ExpirationMetricsVisitor(int taskId) { + MetricsVisitor(int taskId) { mTaskId = taskId; } @@ -78,6 +77,11 @@ BackgroundTaskSchedulerUma.getInstance().reportTaskCreatedAndExpirationState( mTaskId, periodicInfo.expiresAfterWindowEndTime()); } + + @Override + public void visit(TaskInfo.ExactInfo exactInfo) { + BackgroundTaskSchedulerUma.getInstance().reportExactTaskCreated(mTaskId); + } } @Override
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java index 7eb169c..c881e7e6 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java
@@ -19,6 +19,7 @@ import org.chromium.base.VisibleForTesting; import java.util.List; + /** * An implementation of {@link BackgroundTaskSchedulerDelegate} that uses the system * {@link JobScheduler} to schedule jobs. @@ -183,6 +184,12 @@ } mBuilder.setPeriodic(periodicInfo.getIntervalMs()); } + + @Override + public void visit(TaskInfo.ExactInfo exactInfo) { + throw new RuntimeException("Exact tasks should not be scheduled with " + + "JobScheduler."); + } } private static int getJobInfoNetworkTypeFromTaskNetworkType(
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java index 8d5f5c6..40d176e9 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
@@ -139,6 +139,12 @@ } } + /** Reports metrics for creating an exact tasks. */ + public void reportExactTaskCreated(int taskId) { + cacheEvent("Android.BackgroundTaskScheduler.ExactTaskCreated", + toUmaEnumValueFromTaskId(taskId)); + } + /** Reports metrics for task scheduling with the expiration feature activated. */ public void reportTaskCreatedAndExpirationState(int taskId, boolean expires) { if (expires) {
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskInfo.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskInfo.java index 56928212e..79fc74c 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskInfo.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskInfo.java
@@ -52,11 +52,16 @@ * @param periodicInfo object to act on. */ void visit(PeriodicInfo periodicInfo); + /** + * Applies actions on a given {@link ExactInfo}. This affects information regarding + * timing for an exact task. + * @param exactInfo object to act on. + */ + void visit(ExactInfo exactInfo); } /** * Specifies information regarding one-off tasks. - * This is part of a {@link TaskInfo} if the task is NOT a periodic task. */ public static class OneOffInfo implements TimingInfo { private final long mWindowStartTimeMs; @@ -181,7 +186,6 @@ /** * Specifies information regarding periodic tasks. - * This is part of a {@link TaskInfo} if the task is a periodic task. */ public static class PeriodicInfo implements TimingInfo { private final long mIntervalMs; @@ -318,6 +322,68 @@ } } + /** + * Specifies information regarding exact tasks. + */ + static class ExactInfo implements TimingInfo { + private final long mTriggerAtMs; + + private ExactInfo(Builder builder) { + mTriggerAtMs = builder.mTriggerAtMs; + } + + long getTriggerAtMs() { + return mTriggerAtMs; + } + + @Override + public void accept(TimingInfoVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("{"); + sb.append("triggerAtMs: ").append(mTriggerAtMs).append("}"); + return sb.toString(); + } + + /** + * @return a new {@link Builder} object to set the values of the exact task. + */ + static Builder create() { + return new Builder(); + } + + /** + * A helper builder to provide a way to build {@link ExactInfo}. + * + * @see #create() + */ + static final class Builder { + private long mTriggerAtMs; + + /** + * Sets the exact UTC timestamp at which to schedule the exact task. + * @param triggerAtMs the UTC timestamp at which the task should be started. + * @return the {@link Builder} for creating the {@link ExactInfo} object. + */ + Builder setTriggerAtMs(long triggerAtMs) { + mTriggerAtMs = triggerAtMs; + return this; + } + + /** + * Build the {@link ExactInfo object} specified by this builder. + * + * @return the {@link ExactInfo} object. + */ + ExactInfo build() { + return new ExactInfo(this); + } + } + } + @IntDef({NetworkType.NONE, NetworkType.ANY, NetworkType.UNMETERED}) @Retention(RetentionPolicy.SOURCE) public @interface NetworkType {
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java index c56acc9..3b3684b5 100644 --- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java +++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java
@@ -194,6 +194,16 @@ @Test @Feature({"BackgroundTaskScheduler"}) + public void testReportExactTaskCreated() { + doNothing().when(mUmaSpy).cacheEvent(anyString(), anyInt()); + BackgroundTaskSchedulerUma.getInstance().reportExactTaskCreated(TaskIds.TEST); + verify(mUmaSpy, times(1)) + .cacheEvent(eq("Android.BackgroundTaskScheduler.ExactTaskCreated"), + eq(BackgroundTaskSchedulerUma.BACKGROUND_TASK_TEST)); + } + + @Test + @Feature({"BackgroundTaskScheduler"}) public void testReportTaskScheduledWithExpiration() { doNothing().when(mUmaSpy).cacheEvent(anyString(), anyInt()); BackgroundTaskSchedulerUma.getInstance().reportTaskCreatedAndExpirationState(
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TaskInfoTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TaskInfoTest.java index 613cdc0..9c5025f 100644 --- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TaskInfoTest.java +++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TaskInfoTest.java
@@ -6,8 +6,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.Before; @@ -34,9 +32,19 @@ BackgroundTaskSchedulerFactory.setBackgroundTaskFactory(new TestBackgroundTaskFactory()); } - private void checkGeneralTaskInfoFields(TaskInfo taskInfo, int taskId) { - assertEquals(taskId, taskInfo.getTaskId()); - assertEquals(TestBackgroundTask.class, taskInfo.getBackgroundTaskClass()); + @Test + @Feature({"BackgroundTaskScheduler"}) + public void testGeneralFields() { + TaskInfo.TimingInfo timingInfo = TaskInfo.OneOffInfo.create() + .setWindowEndTimeMs(TEST_END_MS) + .setExpiresAfterWindowEndTime(true) + .build(); + TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build(); + + assertEquals(TaskIds.TEST, oneOffTask.getTaskId()); + assertEquals(TestBackgroundTask.class, + BackgroundTaskSchedulerFactory.getBackgroundTaskFromTaskId(TaskIds.TEST) + .getClass()); } @Test @@ -47,15 +55,8 @@ .setExpiresAfterWindowEndTime(true) .build(); TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build(); - - checkGeneralTaskInfoFields(oneOffTask, TaskIds.TEST); - - assertFalse(oneOffTask.getOneOffInfo().hasWindowStartTimeConstraint()); - assertEquals(TEST_END_MS, oneOffTask.getOneOffInfo().getWindowEndTimeMs()); - assertTrue(oneOffTask.getOneOffInfo().expiresAfterWindowEndTime()); - - assertNotNull(oneOffTask.getOneOffInfo()); - assertNull(oneOffTask.getPeriodicInfo()); + CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(null, TEST_END_MS, true); + oneOffTask.getTimingInfo().accept(visitor); } @Test @@ -67,11 +68,9 @@ .setExpiresAfterWindowEndTime(true) .build(); TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build(); - - assertTrue(oneOffTask.getOneOffInfo().hasWindowStartTimeConstraint()); - assertEquals(TEST_START_MS, oneOffTask.getOneOffInfo().getWindowStartTimeMs()); - assertEquals(TEST_END_MS, oneOffTask.getOneOffInfo().getWindowEndTimeMs()); - assertTrue(oneOffTask.getOneOffInfo().expiresAfterWindowEndTime()); + CheckTimingInfoVisitor visitor = + new CheckTimingInfoVisitor(TEST_START_MS, TEST_END_MS, true); + oneOffTask.getTimingInfo().accept(visitor); } @Test @@ -83,10 +82,8 @@ .setExpiresAfterWindowEndTime(true) .build(); TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build(); - - assertEquals(TEST_END_MS, oneOffTask.getOneOffInfo().getWindowStartTimeMs()); - assertEquals(TEST_END_MS, oneOffTask.getOneOffInfo().getWindowEndTimeMs()); - assertTrue(oneOffTask.getOneOffInfo().expiresAfterWindowEndTime()); + CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(TEST_END_MS, TEST_END_MS, true); + oneOffTask.getTimingInfo().accept(visitor); } @Test @@ -94,10 +91,8 @@ public void testOneOffNoParamsSet() { TaskInfo.TimingInfo timingInfo = TaskInfo.OneOffInfo.create().build(); TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build(); - - assertFalse(oneOffTask.getOneOffInfo().hasWindowStartTimeConstraint()); - assertEquals(0, oneOffTask.getOneOffInfo().getWindowEndTimeMs()); - assertFalse(oneOffTask.getOneOffInfo().expiresAfterWindowEndTime()); + CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(null, new Long(0), false); + oneOffTask.getTimingInfo().accept(visitor); } @Test @@ -108,14 +103,8 @@ .setExpiresAfterWindowEndTime(true) .build(); TaskInfo periodicTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build(); - - checkGeneralTaskInfoFields(periodicTask, TaskIds.TEST); - - assertFalse(periodicTask.getPeriodicInfo().hasFlex()); - assertEquals(TEST_END_MS, periodicTask.getPeriodicInfo().getIntervalMs()); - assertTrue(periodicTask.getPeriodicInfo().expiresAfterWindowEndTime()); - - assertEquals(null, periodicTask.getOneOffInfo()); + CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(TEST_END_MS, null, true); + periodicTask.getTimingInfo().accept(visitor); } @Test @@ -127,11 +116,9 @@ .setExpiresAfterWindowEndTime(true) .build(); TaskInfo periodicTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build(); - - assertTrue(periodicTask.getPeriodicInfo().hasFlex()); - assertEquals(TEST_FLEX_MS, periodicTask.getPeriodicInfo().getFlexMs()); - assertEquals(TEST_END_MS, periodicTask.getPeriodicInfo().getIntervalMs()); - assertTrue(periodicTask.getPeriodicInfo().expiresAfterWindowEndTime()); + CheckTimingInfoVisitor visitor = + new CheckTimingInfoVisitor(TEST_END_MS, TEST_FLEX_MS, true); + periodicTask.getTimingInfo().accept(visitor); } @Test @@ -139,9 +126,60 @@ public void testPeriodicNoParamsSet() { TaskInfo.TimingInfo timingInfo = TaskInfo.PeriodicInfo.create().build(); TaskInfo periodicTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build(); + CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(new Long(0), null, false); + periodicTask.getTimingInfo().accept(visitor); + } - assertFalse(periodicTask.getPeriodicInfo().hasFlex()); - assertEquals(0, periodicTask.getPeriodicInfo().getIntervalMs()); - assertFalse(periodicTask.getPeriodicInfo().expiresAfterWindowEndTime()); + @Test + @Feature({"BackgroundTaskScheduler"}) + public void testExact() { + TaskInfo.TimingInfo timingInfo = + TaskInfo.ExactInfo.create().setTriggerAtMs(TEST_END_MS).build(); + TaskInfo exactOneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build(); + CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(TEST_END_MS, null, false); + exactOneOffTask.getTimingInfo().accept(visitor); + } + + private class CheckTimingInfoVisitor implements TaskInfo.TimingInfoVisitor { + private final Long mStartOrIntervalOrTriggerMs; + private final Long mEndOrFlexMs; + private final boolean mExpires; + + CheckTimingInfoVisitor(Long startOrIntervalOrTriggerMs, Long endOrFlexMs, boolean expires) { + mStartOrIntervalOrTriggerMs = startOrIntervalOrTriggerMs; + mEndOrFlexMs = endOrFlexMs; + mExpires = expires; + } + + @Override + public void visit(TaskInfo.OneOffInfo oneOffInfo) { + if (mStartOrIntervalOrTriggerMs == null) { + assertFalse(oneOffInfo.hasWindowStartTimeConstraint()); + } else { + assertTrue(oneOffInfo.hasWindowStartTimeConstraint()); + assertEquals( + mStartOrIntervalOrTriggerMs.longValue(), oneOffInfo.getWindowStartTimeMs()); + } + + assertEquals(mEndOrFlexMs.longValue(), oneOffInfo.getWindowEndTimeMs()); + assertEquals(mExpires, oneOffInfo.expiresAfterWindowEndTime()); + } + + @Override + public void visit(TaskInfo.PeriodicInfo periodicInfo) { + assertEquals(mStartOrIntervalOrTriggerMs.longValue(), periodicInfo.getIntervalMs()); + + if (mEndOrFlexMs == null) { + assertFalse(periodicInfo.hasFlex()); + } else { + assertTrue(periodicInfo.hasFlex()); + assertEquals(mEndOrFlexMs.longValue(), periodicInfo.getFlexMs()); + } + } + + @Override + public void visit(TaskInfo.ExactInfo exactInfo) { + assertEquals(mStartOrIntervalOrTriggerMs.longValue(), exactInfo.getTriggerAtMs()); + } } } \ No newline at end of file
diff --git a/components/flags_ui/flags_state.cc b/components/flags_ui/flags_state.cc index b1d4685..564df9e 100644 --- a/components/flags_ui/flags_state.cc +++ b/components/flags_ui/flags_state.cc
@@ -34,9 +34,6 @@ const char kTrialGroupAboutFlags[] = "AboutFlags"; } // namespace internal -const base::Feature kUnexpireFlagsM78{"TemporaryUnexpireFlagsM78", - base::FEATURE_DISABLED_BY_DEFAULT}; - namespace { // Separator used for origin list values. The list of origins provided from
diff --git a/components/flags_ui/flags_state.h b/components/flags_ui/flags_state.h index 324f76da5..068c53d7 100644 --- a/components/flags_ui/flags_state.h +++ b/components/flags_ui/flags_state.h
@@ -46,8 +46,6 @@ kEnterprise = 1 << 7, }; -extern const base::Feature kUnexpireFlagsM78; - // A flag controlling the behavior of the |ConvertFlagsToSwitches| function - // whether it should add the sentinel switches around flags. enum SentinelsMode { kNoSentinels, kAddSentinels };
diff --git a/components/history/core/browser/thumbnail_database.cc b/components/history/core/browser/thumbnail_database.cc index cfc3a9c..05d43e7 100644 --- a/components/history/core/browser/thumbnail_database.cc +++ b/components/history/core/browser/thumbnail_database.cc
@@ -1047,6 +1047,7 @@ if (!db->Open(db_name)) return sql::INIT_FAILURE; + db->Preload(); return sql::INIT_OK; }
diff --git a/components/media_message_center/media_notification_background.cc b/components/media_message_center/media_notification_background.cc index 3d6f49f33..73fe210 100644 --- a/components/media_message_center/media_notification_background.cc +++ b/components/media_message_center/media_notification_background.cc
@@ -233,16 +233,12 @@ } // namespace MediaNotificationBackground::MediaNotificationBackground( - views::View* owner, int top_radius, int bottom_radius, double artwork_max_width_pct) - : owner_(owner), - top_radius_(top_radius), + : top_radius_(top_radius), bottom_radius_(bottom_radius), - artwork_max_width_pct_(artwork_max_width_pct) { - DCHECK(owner); -} + artwork_max_width_pct_(artwork_max_width_pct) {} MediaNotificationBackground::~MediaNotificationBackground() = default; @@ -274,7 +270,7 @@ // maintaining the aspect ratio. gfx::Rect source_bounds = gfx::Rect(0, 0, artwork_.width(), artwork_.height()); - gfx::Rect artwork_bounds = GetArtworkBounds(bounds); + gfx::Rect artwork_bounds = GetArtworkBounds(*view); canvas->DrawImageInt( artwork_, source_bounds.x(), source_bounds.y(), source_bounds.width(), @@ -286,11 +282,11 @@ // notification. This may cover up some of the artwork. const SkColor background_color = background_color_.value_or(kMediaNotificationDefaultBackgroundColor); - canvas->FillRect(GetFilledBackgroundBounds(bounds), background_color); + canvas->FillRect(GetFilledBackgroundBounds(*view), background_color); { // Draw a gradient to fade the color background and the image together. - gfx::Rect draw_bounds = GetGradientBounds(bounds); + gfx::Rect draw_bounds = GetGradientBounds(*view); const SkColor colors[2] = { background_color, SkColorSetA(background_color, SK_AlphaTRANSPARENT)}; @@ -315,27 +311,25 @@ background_color_ = GetNotificationBackgroundColor(artwork_.bitmap()); foreground_color_ = GetNotificationForegroundColor(background_color_, artwork_.bitmap()); - owner_->SchedulePaint(); } -void MediaNotificationBackground::UpdateCornerRadius(int top_radius, +bool MediaNotificationBackground::UpdateCornerRadius(int top_radius, int bottom_radius) { if (top_radius_ == top_radius && bottom_radius_ == bottom_radius) - return; + return false; top_radius_ = top_radius; bottom_radius_ = bottom_radius; - - owner_->SchedulePaint(); + return true; } -void MediaNotificationBackground::UpdateArtworkMaxWidthPct( +bool MediaNotificationBackground::UpdateArtworkMaxWidthPct( double max_width_pct) { if (artwork_max_width_pct_ == max_width_pct) - return; + return false; artwork_max_width_pct_ = max_width_pct; - owner_->SchedulePaint(); + return true; } SkColor MediaNotificationBackground::GetBackgroundColor() const { @@ -344,11 +338,12 @@ return kMediaNotificationDefaultBackgroundColor; } -SkColor MediaNotificationBackground::GetForegroundColor() const { +SkColor MediaNotificationBackground::GetForegroundColor( + const views::View& owner) const { const SkColor foreground = foreground_color_.has_value() ? *foreground_color_ - : views::style::GetColor(*owner_, views::style::CONTEXT_LABEL, + : views::style::GetColor(owner, views::style::CONTEXT_LABEL, views::style::STYLE_PRIMARY); return color_utils::BlendForMinContrast(foreground, GetBackgroundColor()) .color; @@ -373,31 +368,34 @@ } gfx::Rect MediaNotificationBackground::GetArtworkBounds( - const gfx::Rect& view_bounds) const { + const views::View& owner) const { + const gfx::Rect& view_bounds = owner.GetContentsBounds(); int width = GetArtworkWidth(view_bounds.size()); // The artwork should be positioned on the far right hand side of the // notification and be the same height. - return owner_->GetMirroredRect( + return owner.GetMirroredRect( gfx::Rect(view_bounds.right() - width, 0, width, view_bounds.height())); } gfx::Rect MediaNotificationBackground::GetFilledBackgroundBounds( - const gfx::Rect& view_bounds) const { + const views::View& owner) const { // The filled background should take up the full notification except the area // taken up by the artwork. + const gfx::Rect& view_bounds = owner.GetContentsBounds(); gfx::Rect bounds = gfx::Rect(view_bounds); bounds.Inset(0, 0, GetArtworkVisibleWidth(view_bounds.size()), 0); - return owner_->GetMirroredRect(bounds); + return owner.GetMirroredRect(bounds); } gfx::Rect MediaNotificationBackground::GetGradientBounds( - const gfx::Rect& view_bounds) const { + const views::View& owner) const { if (artwork_.isNull()) return gfx::Rect(0, 0, 0, 0); // The gradient should appear above the artwork on the left. - return owner_->GetMirroredRect(gfx::Rect( + const gfx::Rect& view_bounds = owner.GetContentsBounds(); + return owner.GetMirroredRect(gfx::Rect( view_bounds.width() - GetArtworkVisibleWidth(view_bounds.size()), view_bounds.y(), kMediaImageGradientWidth, view_bounds.height())); }
diff --git a/components/media_message_center/media_notification_background.h b/components/media_message_center/media_notification_background.h index 8953a20..357e8bd8 100644 --- a/components/media_message_center/media_notification_background.h +++ b/components/media_message_center/media_notification_background.h
@@ -29,8 +29,7 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationBackground : public views::Background { public: - MediaNotificationBackground(views::View* owner, - int top_radius, + MediaNotificationBackground(int top_radius, int bottom_radius, double artwork_max_width_pct); ~MediaNotificationBackground() override; @@ -38,12 +37,12 @@ // views::Background void Paint(gfx::Canvas* canvas, views::View* view) const override; - void UpdateCornerRadius(int top_radius, int bottom_radius); void UpdateArtwork(const gfx::ImageSkia& image); - void UpdateArtworkMaxWidthPct(double max_width_pct); + bool UpdateCornerRadius(int top_radius, int bottom_radius); + bool UpdateArtworkMaxWidthPct(double max_width_pct); SkColor GetBackgroundColor() const; - SkColor GetForegroundColor() const; + SkColor GetForegroundColor(const views::View& owner) const; private: friend class MediaNotificationBackgroundTest; @@ -53,15 +52,12 @@ int GetArtworkWidth(const gfx::Size& view_size) const; int GetArtworkVisibleWidth(const gfx::Size& view_size) const; - gfx::Rect GetArtworkBounds(const gfx::Rect& view_bounds) const; - gfx::Rect GetFilledBackgroundBounds(const gfx::Rect& view_bounds) const; - gfx::Rect GetGradientBounds(const gfx::Rect& view_bounds) const; + gfx::Rect GetArtworkBounds(const views::View& owner) const; + gfx::Rect GetFilledBackgroundBounds(const views::View& owner) const; + gfx::Rect GetGradientBounds(const views::View& owner) const; SkPoint GetGradientStartPoint(const gfx::Rect& draw_bounds) const; SkPoint GetGradientEndPoint(const gfx::Rect& draw_bounds) const; - // Reference to the owning view that this is a background for. - views::View* owner_; - int top_radius_; int bottom_radius_;
diff --git a/components/media_message_center/media_notification_background_unittest.cc b/components/media_message_center/media_notification_background_unittest.cc index 4b58881..f73819f 100644 --- a/components/media_message_center/media_notification_background_unittest.cc +++ b/components/media_message_center/media_notification_background_unittest.cc
@@ -73,16 +73,13 @@ ~MediaNotificationBackgroundTest() override = default; void SetUp() override { - owner_ = std::make_unique<views::StaticSizedView>(); - background_ = std::make_unique<MediaNotificationBackground>(owner_.get(), - 10, 10, 0.1); + background_ = std::make_unique<MediaNotificationBackground>(10, 10, 0.1); EXPECT_FALSE(GetBackgroundColor().has_value()); } void TearDown() override { background_.reset(); - owner_.reset(); } MediaNotificationBackground* background() const { return background_.get(); } @@ -96,7 +93,6 @@ } private: - std::unique_ptr<views::StaticSizedView> owner_; std::unique_ptr<MediaNotificationBackground> background_; DISALLOW_COPY_AND_ASSIGN(MediaNotificationBackgroundTest); @@ -322,6 +318,8 @@ : switches::kForceDirectionLTR); MediaNotificationBackgroundTest::SetUp(); + + ASSERT_EQ(IsRTL(), base::i18n::IsRTL()); } bool IsRTL() const { return GetParam(); } @@ -336,15 +334,19 @@ TEST_P(MediaNotificationBackgroundRTLTest, BoundsSanityCheck) { // The test notification will have a width of 200 and a height of 50. gfx::Rect bounds(0, 0, 200, 50); + auto owner = std::make_unique<views::StaticSizedView>(); + owner->SetBoundsRect(bounds); + ASSERT_EQ(bounds, owner->GetContentsBounds()); // Check the artwork is not visible by default. EXPECT_EQ(0, background()->GetArtworkWidth(bounds.size())); EXPECT_EQ(0, background()->GetArtworkVisibleWidth(bounds.size())); - EXPECT_EQ(gfx::Rect(IsRTL() ? -200 : 200, 0, 0, 50), - background()->GetArtworkBounds(bounds)); - EXPECT_EQ(gfx::Rect(IsRTL() ? -200 : 0, 0, 200, 50), - background()->GetFilledBackgroundBounds(bounds)); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), background()->GetGradientBounds(bounds)); + EXPECT_EQ(gfx::Rect(IsRTL() ? 0 : 200, 0, 0, 50), + background()->GetArtworkBounds(*owner.get())); + EXPECT_EQ(gfx::Rect(IsRTL() ? 0 : 0, 0, 200, 50), + background()->GetFilledBackgroundBounds(*owner.get())); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), + background()->GetGradientBounds(*owner.get())); // The background artwork image will have an aspect ratio of 2:1. SkBitmap bitmap; @@ -362,22 +364,22 @@ EXPECT_EQ(100, background()->GetArtworkVisibleWidth(bounds.size())); // Check the artwork is positioned to the right. - EXPECT_EQ(gfx::Rect(IsRTL() ? -200 : 100, 0, 100, 50), - background()->GetArtworkBounds(bounds)); + EXPECT_EQ(gfx::Rect(IsRTL() ? 0 : 100, 0, 100, 50), + background()->GetArtworkBounds(*owner.get())); // Check the filled background is to the left of the image. - EXPECT_EQ(gfx::Rect(IsRTL() ? -100 : 0, 0, 100, 50), - background()->GetFilledBackgroundBounds(bounds)); + EXPECT_EQ(gfx::Rect(IsRTL() ? 100 : 0, 0, 100, 50), + background()->GetFilledBackgroundBounds(*owner.get())); // Check the gradient is positioned above the artwork. - const gfx::Rect gradient_bounds = background()->GetGradientBounds(bounds); - EXPECT_EQ(gfx::Rect(IsRTL() ? -140 : 100, 0, 40, 50), gradient_bounds); + const gfx::Rect gradient_bounds = + background()->GetGradientBounds(*owner.get()); + EXPECT_EQ(gfx::Rect(IsRTL() ? 60 : 100, 0, 40, 50), gradient_bounds); // Check the gradient point X-values are the start and end of // |gradient_bounds|. - EXPECT_EQ(IsRTL() ? -100 : 100, - background()->GetGradientStartPoint(gradient_bounds).x()); - EXPECT_EQ(IsRTL() ? -140 : 140, + EXPECT_EQ(100, background()->GetGradientStartPoint(gradient_bounds).x()); + EXPECT_EQ(IsRTL() ? 60 : 140, background()->GetGradientEndPoint(gradient_bounds).x()); // Check both of the gradient point Y-values are half the height.
diff --git a/components/media_message_center/media_notification_view.cc b/components/media_message_center/media_notification_view.cc index c645937..dbf1d5f 100644 --- a/components/media_message_center/media_notification_view.cc +++ b/components/media_message_center/media_notification_view.cc
@@ -203,7 +203,7 @@ IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_NEXT_TRACK)); SetBackground(std::make_unique<MediaNotificationBackground>( - this, message_center::kNotificationCornerRadius, + message_center::kNotificationCornerRadius, message_center::kNotificationCornerRadius, kMediaImageMaxWidthPct)); UpdateForegroundColor(); @@ -235,8 +235,10 @@ void MediaNotificationView::UpdateCornerRadius(int top_radius, int bottom_radius) { - GetMediaNotificationBackground()->UpdateCornerRadius(top_radius, - bottom_radius); + if (GetMediaNotificationBackground()->UpdateCornerRadius(top_radius, + bottom_radius)) { + SchedulePaint(); + } } void MediaNotificationView::GetAccessibleNodeData(ui::AXNodeData* node_data) { @@ -394,8 +396,10 @@ main_row_->Layout(); - GetMediaNotificationBackground()->UpdateArtworkMaxWidthPct( - expanded ? kMediaImageMaxWidthExpandedPct : kMediaImageMaxWidthPct); + if (GetMediaNotificationBackground()->UpdateArtworkMaxWidthPct( + expanded ? kMediaImageMaxWidthExpandedPct : kMediaImageMaxWidthPct)) { + SchedulePaint(); + } header_row_->SetExpanded(expanded); @@ -439,7 +443,7 @@ const SkColor background = GetMediaNotificationBackground()->GetBackgroundColor(); const SkColor foreground = - GetMediaNotificationBackground()->GetForegroundColor(); + GetMediaNotificationBackground()->GetForegroundColor(*this); title_label_->SetEnabledColor(foreground); artist_label_->SetEnabledColor(foreground);
diff --git a/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc b/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc index 139c87d3..c23a406 100644 --- a/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc +++ b/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc
@@ -31,7 +31,7 @@ using ::testing::StrictMock; constexpr char kTestEmail[] = "user@gmail.com"; -constexpr char kUsername[] = "username"; +constexpr char kUsername[] = "USERNAME@gmail.com"; constexpr char kPassword[] = "password123"; constexpr char kExampleCom[] = "https://example.com"; @@ -333,13 +333,20 @@ PayloadAndCallback payload_and_callback = ImitateNetworkRequest(); ASSERT_TRUE(!payload_and_callback.payload.empty()); + // |canonicalized_username| is passed to ScryptHashUsernameAndPassword() to + // make sure the canonicalization logic works correctly. Assert that + // CanonicalizeUsername() was not a no-op. + std::string canonicalized_username = CanonicalizeUsername(kUsername); + ASSERT_NE(kUsername, canonicalized_username); + auto response = std::make_unique<SingleLookupResponse>(); std::string key_server; response->reencrypted_lookup_hash = CipherReEncrypt(payload_and_callback.payload, &key_server); response->encrypted_leak_match_prefixes.push_back( crypto::SHA256HashString(CipherEncryptWithKey( - ScryptHashUsernameAndPassword(kUsername, kPassword), key_server))); + ScryptHashUsernameAndPassword(canonicalized_username, kPassword), + key_server))); EXPECT_CALL(delegate(), OnLeakDetectionDone(true, GURL(kExampleCom), base::ASCIIToUTF16(kUsername),
diff --git a/components/password_manager/core/browser/leak_detection/encryption_utils.cc b/components/password_manager/core/browser/leak_detection/encryption_utils.cc index 0ba2198..36da42d 100644 --- a/components/password_manager/core/browser/leak_detection/encryption_utils.cc +++ b/components/password_manager/core/browser/leak_detection/encryption_utils.cc
@@ -35,6 +35,10 @@ 120, 112, 44, 114, 24, 86, 84, -103, -77, -23, 33, 24, 108, 33, 26, 1, 34, 60, 69, 74, -6}; + // Check that |canonicalized_username| is actually canonicalized. + // Note: We can't use CanonicalizeUsername() again, since it's not idempotent + // if multiple '@' signs are present in the initial username. + DCHECK_EQ(base::ToLowerASCII(canonicalized_username), canonicalized_username); return crypto::SHA256HashString(base::StrCat( {canonicalized_username, base::StringPiece(kUsernameSalt, base::size(kUsernameSalt))})); @@ -44,13 +48,19 @@ static_assert( kUsernameHashPrefixLength % CHAR_BIT == 0, "The prefix length must be a multiple of the number of bits in a char."); + + // Check that |canonicalized_username| is actually canonicalized. + // Note: We can't use CanonicalizeUsername() again, since it's not idempotent + // if multiple '@' signs are present in the initial username. + DCHECK_EQ(base::ToLowerASCII(canonicalized_username), canonicalized_username); return HashUsername(canonicalized_username) .substr(0, kUsernameHashPrefixLength / CHAR_BIT); } -std::string ScryptHashUsernameAndPassword(base::StringPiece username, - base::StringPiece password) { - // Constant salt added to the password hash on top of username. +std::string ScryptHashUsernameAndPassword( + base::StringPiece canonicalized_username, + base::StringPiece password) { + // Constant salt added to the password hash on top of canonicalized_username. // Needs to stay in sync with server side constant: go/passwords-leak-salts static constexpr char kPasswordHashSalt[] = { 48, 118, 42, -46, 63, 123, -95, -101, -8, -29, 66, @@ -62,10 +72,15 @@ static constexpr uint64_t kScryptParallelization = 1; static constexpr size_t kScryptMaxMemory = 1024 * 1024 * 32; + // Check that |canonicalized_username| is actually canonicalized. + // Note: We can't use CanonicalizeUsername() again, since it's not idempotent + // if multiple '@' signs are present in the initial username. + DCHECK_EQ(base::ToLowerASCII(canonicalized_username), canonicalized_username); crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); - std::string username_password = base::StrCat({username, password}); + std::string username_password = + base::StrCat({canonicalized_username, password}); std::string salt = base::StrCat( - {username, + {canonicalized_username, base::StringPiece(kPasswordHashSalt, base::size(kPasswordHashSalt))}); std::string result;
diff --git a/components/password_manager/core/browser/leak_detection/encryption_utils.h b/components/password_manager/core/browser/leak_detection/encryption_utils.h index fe7d90d..ec6a3bce 100644 --- a/components/password_manager/core/browser/leak_detection/encryption_utils.h +++ b/components/password_manager/core/browser/leak_detection/encryption_utils.h
@@ -28,9 +28,10 @@ std::string BucketizeUsername(base::StringPiece canonicalized_username); // Produces the username/password pair hash using scrypt algorithm. -// |username| and |password| are UTF-8 strings. -std::string ScryptHashUsernameAndPassword(base::StringPiece username, - base::StringPiece password); +// |canonicalized_username| and |password| are UTF-8 strings. +std::string ScryptHashUsernameAndPassword( + base::StringPiece canonicalized_username, + base::StringPiece password); // Encrypt/decrypt routines.
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc index 279be21..9d61252 100644 --- a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc +++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
@@ -22,10 +22,12 @@ // asynchronously. LookupSingleLeakData PrepareLookupSingleLeakData(const std::string& username, const std::string& password) { + std::string canonicalized_username = CanonicalizeUsername(username); LookupSingleLeakData data; - data.username_hash_prefix = BucketizeUsername(CanonicalizeUsername(username)); + data.username_hash_prefix = BucketizeUsername(canonicalized_username); data.encrypted_payload = CipherEncrypt( - ScryptHashUsernameAndPassword(username, password), &data.encryption_key); + ScryptHashUsernameAndPassword(canonicalized_username, password), + &data.encryption_key); return data; }
diff --git a/components/password_manager/core/browser/sync_credentials_filter_unittest.cc b/components/password_manager/core/browser/sync_credentials_filter_unittest.cc index 04bf66b0..dc57f9b6 100644 --- a/components/password_manager/core/browser/sync_credentials_filter_unittest.cc +++ b/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
@@ -19,7 +19,7 @@ #include "components/autofill/core/common/password_form.h" #include "components/password_manager/core/browser/fake_form_fetcher.h" #include "components/password_manager/core/browser/mock_password_store.h" -#include "components/password_manager/core/browser/password_manager.h" +#include "components/password_manager/core/browser/new_password_form_manager.h" #include "components/password_manager/core/browser/password_manager_test_utils.h" #include "components/password_manager/core/browser/stub_form_saver.h" #include "components/password_manager/core/browser/stub_password_manager_client.h" @@ -111,18 +111,16 @@ CredentialsFilterTest() : client_(identity_manager()), - password_manager_(&client_), pending_(SimpleGaiaForm("user@gmail.com")), - form_manager_(&password_manager_, - &client_, + form_manager_(&client_, driver_.AsWeakPtr(), - pending_, + pending_.form_data, + &fetcher_, std::make_unique<StubFormSaver>(), - &fetcher_), + nullptr /* metrics_recorder */), filter_(&client_, base::BindRepeating(&SyncUsernameTestBase::sync_service, base::Unretained(this))) { - form_manager_.Init(nullptr); fetcher_.Fetch(); } @@ -137,16 +135,15 @@ fetcher_.SetNonFederated(matches); fetcher_.NotifyFetchCompleted(); - form_manager_.ProvisionallySave(pending_); + form_manager_.ProvisionallySave(pending_.form_data, &driver_); } protected: FakePasswordManagerClient client_; - PasswordManager password_manager_; StubPasswordManagerDriver driver_; PasswordForm pending_; FakeFormFetcher fetcher_; - PasswordFormManager form_manager_; + NewPasswordFormManager form_manager_; SyncCredentialsFilter filter_; };
diff --git a/components/password_manager/core/browser/sync_username_test_base.cc b/components/password_manager/core/browser/sync_username_test_base.cc index bf541ac..d23c5daf 100644 --- a/components/password_manager/core/browser/sync_username_test_base.cc +++ b/components/password_manager/core/browser/sync_username_test_base.cc
@@ -5,11 +5,35 @@ #include "components/password_manager/core/browser/sync_username_test_base.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/common/form_data.h" +using autofill::FormData; +using autofill::FormFieldData; using autofill::PasswordForm; +using base::ASCIIToUTF16; namespace password_manager { +namespace { + +FormData CreateSigninFormData(const GURL& url, const char* username) { + FormData form; + form.url = url; + FormFieldData field; + field.name = ASCIIToUTF16("username_element"); + field.form_control_type = "text"; + field.value = ASCIIToUTF16(username); + form.fields.push_back(field); + + field.name = ASCIIToUTF16("password_element"); + field.form_control_type = "password"; + field.value = ASCIIToUTF16("strong_pw"); + form.fields.push_back(field); + return form; +} + +} // namespace + SyncUsernameTestBase::SyncUsernameTestBase() = default; SyncUsernameTestBase::~SyncUsernameTestBase() = default; @@ -32,7 +56,8 @@ PasswordForm SyncUsernameTestBase::SimpleGaiaForm(const char* username) { PasswordForm form; form.signon_realm = "https://accounts.google.com"; - form.username_value = base::ASCIIToUTF16(username); + form.username_value = ASCIIToUTF16(username); + form.form_data = CreateSigninFormData(GURL(form.signon_realm), username); return form; } @@ -40,7 +65,8 @@ PasswordForm SyncUsernameTestBase::SimpleNonGaiaForm(const char* username) { PasswordForm form; form.signon_realm = "https://site.com"; - form.username_value = base::ASCIIToUTF16(username); + form.username_value = ASCIIToUTF16(username); + form.form_data = CreateSigninFormData(GURL(form.signon_realm), username); return form; } @@ -49,8 +75,9 @@ const char* origin) { PasswordForm form; form.signon_realm = "https://site.com"; - form.username_value = base::ASCIIToUTF16(username); + form.username_value = ASCIIToUTF16(username); form.origin = GURL(origin); + form.form_data = CreateSigninFormData(GURL(form.signon_realm), username); return form; }
diff --git a/components/sessions/content/content_serialized_navigation_builder.cc b/components/sessions/content/content_serialized_navigation_builder.cc index 4bd035d..54e9345 100644 --- a/components/sessions/content/content_serialized_navigation_builder.cc +++ b/components/sessions/content/content_serialized_navigation_builder.cc
@@ -4,6 +4,8 @@ #include "components/sessions/content/content_serialized_navigation_builder.h" +#include <string> + #include "base/logging.h" #include "components/sessions/content/content_record_password_state.h" #include "components/sessions/content/content_serialized_navigation_driver.h" @@ -88,19 +90,15 @@ ContentSerializedNavigationBuilder::ToNavigationEntry( const SerializedNavigationEntry* navigation, content::BrowserContext* browser_context) { - // TODO(lukasza): https://crbug.com/976055: |initiator_origin| should be - // persisted across session restore. - base::Optional<url::Origin> initiator_origin = base::nullopt; + // The initial values of the NavigationEntry are only temporary - they + // will get cloberred by one of the SetPageState calls below. + GURL temporary_url; + content::Referrer temporary_referrer; + base::Optional<url::Origin> temporary_initiator_origin = base::nullopt; - network::mojom::ReferrerPolicy policy = - static_cast<network::mojom::ReferrerPolicy>(navigation->referrer_policy_); std::unique_ptr<content::NavigationEntry> entry( content::NavigationController::CreateNavigationEntry( - navigation->virtual_url_, - content::Referrer::SanitizeForRequest( - navigation->virtual_url_, - content::Referrer(navigation->referrer_url_, policy)), - initiator_origin, + temporary_url, temporary_referrer, temporary_initiator_origin, // Use a transition type of reload so that we don't incorrectly // increase the typed count. ui::PAGE_TRANSITION_RELOAD, false, @@ -109,8 +107,20 @@ nullptr /* blob_url_loader_factory */)); entry->SetTitle(navigation->title_); - entry->SetPageState(content::PageState::CreateFromEncodedData( - navigation->encoded_page_state_)); + if (navigation->encoded_page_state_.empty()) { + // Conjure a new PageState, based on the URL. + // + // One case where the PageState may be empty is WebUI pages - see + // ChromeSerializedNavigationDriver::Sanitize. Another case is tests for + // "foreign" session restore entries, such as + // SessionRestoreTest.RestoreForeignTab. + entry->SetPageState( + content::PageState::CreateFromURL(navigation->virtual_url_)); + } else { + // Restore PageState. + entry->SetPageState(content::PageState::CreateFromEncodedData( + navigation->encoded_page_state_)); + } entry->SetHasPostData(navigation->has_post_data_); entry->SetPostID(navigation->post_id_); entry->SetOriginalRequestURL(navigation->original_request_url_); @@ -118,6 +128,7 @@ entry->SetTimestamp(navigation->timestamp_); entry->SetHttpStatusCode(navigation->http_status_code_); entry->SetRedirectChain(navigation->redirect_chain_); + entry->SetVirtualURL(navigation->virtual_url_); sessions::NavigationTaskId* navigation_task_id = sessions::NavigationTaskId::Get(entry.get()); navigation_task_id->set_id(navigation->task_id());
diff --git a/components/sessions/content/content_serialized_navigation_builder_unittest.cc b/components/sessions/content/content_serialized_navigation_builder_unittest.cc index d7832d1..d293f061 100644 --- a/components/sessions/content/content_serialized_navigation_builder_unittest.cc +++ b/components/sessions/content/content_serialized_navigation_builder_unittest.cc
@@ -4,6 +4,10 @@ #include "components/sessions/content/content_serialized_navigation_builder.h" +#include <memory> +#include <string> +#include <vector> + #include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" #include "components/sessions/content/content_record_password_state.h" @@ -64,10 +68,9 @@ navigation_entry->SetReferrer(content::Referrer( test_data::kReferrerURL, static_cast<network::mojom::ReferrerPolicy>(test_data::kReferrerPolicy))); + navigation_entry->SetURL(test_data::kURL); navigation_entry->SetVirtualURL(test_data::kVirtualURL); navigation_entry->SetTitle(test_data::kTitle); - navigation_entry->SetPageState( - content::PageState::CreateFromEncodedData(test_data::kEncodedPageState)); navigation_entry->SetTransitionType(test_data::kTransitionType); navigation_entry->SetHasPostData(test_data::kHasPostData); navigation_entry->SetPostID(test_data::kPostID); @@ -147,7 +150,8 @@ EXPECT_EQ(test_data::kReferrerPolicy, navigation.referrer_policy()); EXPECT_EQ(test_data::kVirtualURL, navigation.virtual_url()); EXPECT_EQ(test_data::kTitle, navigation.title()); - EXPECT_EQ(test_data::kEncodedPageState, navigation.encoded_page_state()); + EXPECT_EQ(navigation_entry->GetPageState().ToEncodedData(), + navigation.encoded_page_state()); EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( navigation.transition_type(), test_data::kTransitionType)); EXPECT_EQ(test_data::kHasPostData, navigation.has_post_data()); @@ -188,7 +192,7 @@ ContentSerializedNavigationBuilder::FromNavigationEntry( test_data::kIndex, navigation_entry.get(), ContentSerializedNavigationBuilder::DEFAULT); - EXPECT_EQ(test_data::kEncodedPageState, + EXPECT_EQ(navigation_entry->GetPageState().ToEncodedData(), default_navigation.encoded_page_state()); const SerializedNavigationEntry& excluded_page_state_navigation = @@ -218,9 +222,10 @@ EXPECT_EQ(test_data::kReferrerURL, new_navigation_entry->GetReferrer().url); EXPECT_EQ(test_data::kReferrerPolicy, static_cast<int>(new_navigation_entry->GetReferrer().policy)); + EXPECT_EQ(test_data::kURL, new_navigation_entry->GetURL()); EXPECT_EQ(test_data::kVirtualURL, new_navigation_entry->GetVirtualURL()); EXPECT_EQ(test_data::kTitle, new_navigation_entry->GetTitle()); - EXPECT_EQ(test_data::kEncodedPageState, + EXPECT_EQ(old_navigation_entry->GetPageState().ToEncodedData(), new_navigation_entry->GetPageState().ToEncodedData()); EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( new_navigation_entry->GetTransitionType(), ui::PAGE_TRANSITION_RELOAD));
diff --git a/components/sessions/core/serialized_navigation_entry_test_helper.cc b/components/sessions/core/serialized_navigation_entry_test_helper.cc index f5f08bc..8bb74fde 100644 --- a/components/sessions/core/serialized_navigation_entry_test_helper.cc +++ b/components/sessions/core/serialized_navigation_entry_test_helper.cc
@@ -18,7 +18,8 @@ const int kUniqueID = 50; const GURL kReferrerURL = GURL("http://www.referrer.com"); const int kReferrerPolicy = 0; -const GURL kVirtualURL= GURL("http://www.virtual-url.com"); +const GURL kURL = GURL("http://www.url.com"); +const GURL kVirtualURL = GURL("http://www.virtual-url.com"); const base::string16 kTitle = base::ASCIIToUTF16("title"); const std::string kEncodedPageState = "page state"; const ui::PageTransition kTransitionType =
diff --git a/components/sessions/core/serialized_navigation_entry_test_helper.h b/components/sessions/core/serialized_navigation_entry_test_helper.h index 606b235..9e8af07 100644 --- a/components/sessions/core/serialized_navigation_entry_test_helper.h +++ b/components/sessions/core/serialized_navigation_entry_test_helper.h
@@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_SESSIONS_SESSION_TYPES_TEST_HELPER_H_ -#define COMPONENTS_SESSIONS_SESSION_TYPES_TEST_HELPER_H_ +#ifndef COMPONENTS_SESSIONS_CORE_SERIALIZED_NAVIGATION_ENTRY_TEST_HELPER_H_ +#define COMPONENTS_SESSIONS_CORE_SERIALIZED_NAVIGATION_ENTRY_TEST_HELPER_H_ #include <stdint.h> #include <string> +#include <vector> #include "base/macros.h" #include "base/strings/string16.h" @@ -28,6 +29,7 @@ extern const int kUniqueID; extern const GURL kReferrerURL; extern const int kReferrerPolicy; +extern const GURL kURL; extern const GURL kVirtualURL; extern const base::string16 kTitle; extern const std::string kEncodedPageState; @@ -63,6 +65,11 @@ const SerializedNavigationEntry& actual); // Creates a SerializedNavigationEntry using the |test_data| constants above. + // + // Note that the returned SerializedNavigationEntry will have a bogus + // PageState and therefore can only be used in limited unit tests (e.g. it + // will most likely hit DCHECKs/NOTREACHEDs when passed to the //content + // layer). static SerializedNavigationEntry CreateNavigationForTest(); static void SetReferrerPolicy(int policy, @@ -97,6 +104,6 @@ DISALLOW_IMPLICIT_CONSTRUCTORS(SerializedNavigationEntryTestHelper); }; -} // sessions +} // namespace sessions -#endif // COMPONENTS_SESSIONS_SESSION_TYPES_TEST_HELPER_H_ +#endif // COMPONENTS_SESSIONS_CORE_SERIALIZED_NAVIGATION_ENTRY_TEST_HELPER_H_
diff --git a/components/subresource_filter/FILTER_LIST_GENERATION.md b/components/subresource_filter/FILTER_LIST_GENERATION.md index 7b7efa4..1d524cd 100644 --- a/components/subresource_filter/FILTER_LIST_GENERATION.md +++ b/components/subresource_filter/FILTER_LIST_GENERATION.md
@@ -65,12 +65,7 @@ files. Select gzip compression and use `<your_bucket>/site_urls.*.json.gz` as your destination. -Once exported, you can download the files from your bucket and extract them -into a single file for processing: - -```sh -ls site_urls.*.gz | xargs gunzip -c > site_urls -``` +Once exported, you can download the files from your bucket. ## 2. Acquire a filter list in the indexed format Chromium's tools are designed to work with a binary indexed version of filter @@ -89,7 +84,7 @@ ## 3. Generate the smaller filter list ```sh 1. ninja -C out/Release subresource_filter_tools -2. out/Release/subresource_filter_tool --ruleset=easylist_indexed match_rules --input_file=site_urls > ordered_list.txt +2. cat site_urls.*.json.gz | gunzip - | out/Release/subresource_filter_tool --ruleset=easylist_indexed match_rules > ordered_list.txt 3. head -n 1000 ordered_list.txt | cut -d' ' -f2 > smaller_list.txt ```
diff --git a/components/subresource_filter/tools/filter_tool_main.cc b/components/subresource_filter/tools/filter_tool_main.cc index 708e7475..50013aea 100644 --- a/components/subresource_filter/tools/filter_tool_main.cc +++ b/components/subresource_filter/tools/filter_tool_main.cc
@@ -46,20 +46,20 @@ For a given request if a whitelist rule matches as well as a blacklist rule, the whitelist rule is printed but not the blacklist rule. - * match_batch --input_file=<json_file_path> - Like match, except it does the same for each request in a json file. - The file format is one json expression per line. An example line - follows (note: in the file it wouldn't have a line break like this - comment does): + * match_batch [--input_file=<json_file_path>] + Like match, except it does the same for each request in stdin. A json + file path may be provided to use in place of stdin. The input format + is one json expression per line. An example line follows (note: in + the file/input stream it wouldn't have a line break like this comment + does): {"origin":"http://www.example.com/","request_url":"http://www.exam ple.com/foo.js","request_type":"script"} - * match_rules --input_file=<json_file_path> --min_matches=<optional> - For each record in the given whitespace delimited file (see - match_batch for input file format), records the matching rule (see - match command above) and prints all of the matched rules and the - number of times they matched at the end. + * match_rules [--input_file=<json_file_path>] [--min_matches=<optional>] + For each record in the input (see match_batch for input formats), + records the matching rule (see match command above) and prints all of + the matched rules and the number of times they matched at the end. Which rules get recorded: If only a blacklist rule(s) matches, a blacklist rule is @@ -156,18 +156,18 @@ return 1; } - if (!command_line.HasSwitch(kSwitchInputFile)) { - PrintHelp(); - return 1; + std::ifstream requests_stream; + std::istream* input_stream = &std::cin; + if (command_line.HasSwitch(kSwitchInputFile)) { + requests_stream = + std::ifstream(command_line.GetSwitchValueASCII(kSwitchInputFile)); + input_stream = &requests_stream; } - std::ifstream requests_stream( - command_line.GetSwitchValueASCII(kSwitchInputFile)); - if (cmd == kMatchBatchCommand) { - filter_tool.MatchBatch(&requests_stream); + filter_tool.MatchBatch(input_stream); } else if (cmd == kMatchRulesCommand) { - filter_tool.MatchRules(&requests_stream, min_match_count); + filter_tool.MatchRules(input_stream, min_match_count); } return 0;
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index 532706b..4b99f426 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc
@@ -1851,6 +1851,9 @@ const ui::AXNodeData& data = GetData(); switch (data.role) { + case ax::mojom::Role::kArticle: + return content_client->GetLocalizedString(IDS_AX_ROLE_ARTICLE); + case ax::mojom::Role::kAudio: return content_client->GetLocalizedString(IDS_AX_ROLE_AUDIO); @@ -1877,6 +1880,9 @@ case ax::mojom::Role::kDetails: return content_client->GetLocalizedString(IDS_AX_ROLE_DETAILS); + case ax::mojom::Role::kFigure: + return content_client->GetLocalizedString(IDS_AX_ROLE_FIGURE); + case ax::mojom::Role::kMeter: return content_client->GetLocalizedString(IDS_AX_ROLE_METER);
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc index 15160b96..c2bc69b 100644 --- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc +++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -706,8 +706,10 @@ ax::mojom::Event::kLoadComplete); GURL url( "data:text/html," + "<article></article>" "<audio controls></audio>" "<details></details>" + "<figure></figure>" "<input>" "<input type='color'>" "<input type='date'>" @@ -724,7 +726,7 @@ BrowserAccessibility* root = GetManager()->GetRoot(); ASSERT_NE(nullptr, root); - ASSERT_EQ(12u, root->PlatformChildCount()); + ASSERT_EQ(14u, root->PlatformChildCount()); auto TestLocalizedRoleDescription = [root](int child_index, @@ -737,19 +739,21 @@ }; // For testing purposes, assume we get en-US localized strings. - TestLocalizedRoleDescription(0, base::ASCIIToUTF16("audio")); - TestLocalizedRoleDescription(1, base::ASCIIToUTF16("details")); - TestLocalizedRoleDescription(2, base::ASCIIToUTF16("")); - TestLocalizedRoleDescription(3, base::ASCIIToUTF16("color picker")); - TestLocalizedRoleDescription(4, base::ASCIIToUTF16("date picker")); + TestLocalizedRoleDescription(0, base::ASCIIToUTF16("article")); + TestLocalizedRoleDescription(1, base::ASCIIToUTF16("audio")); + TestLocalizedRoleDescription(2, base::ASCIIToUTF16("details")); + TestLocalizedRoleDescription(3, base::ASCIIToUTF16("figure")); + TestLocalizedRoleDescription(4, base::ASCIIToUTF16("")); + TestLocalizedRoleDescription(5, base::ASCIIToUTF16("color picker")); + TestLocalizedRoleDescription(6, base::ASCIIToUTF16("date picker")); TestLocalizedRoleDescription( - 5, base::ASCIIToUTF16("local date and time picker")); - TestLocalizedRoleDescription(6, base::ASCIIToUTF16("email")); - TestLocalizedRoleDescription(7, base::ASCIIToUTF16("telephone")); - TestLocalizedRoleDescription(8, base::ASCIIToUTF16("url")); - TestLocalizedRoleDescription(9, base::ASCIIToUTF16("week picker")); - TestLocalizedRoleDescription(10, base::ASCIIToUTF16("meter")); - TestLocalizedRoleDescription(11, base::ASCIIToUTF16("output")); + 7, base::ASCIIToUTF16("local date and time picker")); + TestLocalizedRoleDescription(8, base::ASCIIToUTF16("email")); + TestLocalizedRoleDescription(9, base::ASCIIToUTF16("telephone")); + TestLocalizedRoleDescription(10, base::ASCIIToUTF16("url")); + TestLocalizedRoleDescription(11, base::ASCIIToUTF16("week picker")); + TestLocalizedRoleDescription(12, base::ASCIIToUTF16("meter")); + TestLocalizedRoleDescription(13, base::ASCIIToUTF16("output")); } IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc index fa015980..840597a7 100644 --- a/content/browser/appcache/appcache_storage_impl.cc +++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -50,8 +50,6 @@ // Hard coded default when not using quota management. constexpr const int kDefaultQuota = 5 * kMB; -constexpr const int kMaxAppCacheMemDiskCacheSize = 10 * kMB; - constexpr base::FilePath::CharType kDiskCacheDirectoryName[] = FILE_PATH_LITERAL("Cache"); constexpr base::FilePath::CharType kAppCacheDatabaseName[] = @@ -1850,9 +1848,8 @@ disk_cache_ = std::make_unique<AppCacheDiskCache>(); if (is_incognito_) { rv = disk_cache_->InitWithMemBackend( - kMaxAppCacheMemDiskCacheSize, - base::BindOnce(&AppCacheStorageImpl::OnDiskCacheInitialized, - base::Unretained(this))); + 0, base::BindOnce(&AppCacheStorageImpl::OnDiskCacheInitialized, + base::Unretained(this))); } else { expecting_cleanup_complete_on_disable_ = true;
diff --git a/content/browser/browsing_data/browsing_data_browsertest_utils.cc b/content/browser/browsing_data/browsing_data_browsertest_utils.cc new file mode 100644 index 0000000..521b264a --- /dev/null +++ b/content/browser/browsing_data/browsing_data_browsertest_utils.cc
@@ -0,0 +1,177 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/browsing_data/browsing_data_browsertest_utils.h" + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/run_loop.h" +#include "base/task/post_task.h" +#include "components/network_session_configurator/common/network_switches.h" +#include "content/browser/browsing_data/browsing_data_test_utils.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/browser/storage_usage_info.h" +#include "content/public/browser/system_connector.h" +#include "content/public/common/content_switches.h" +#include "content/public/common/network_service_util.h" +#include "content/public/common/service_names.mojom.h" +#include "content/public/test/content_browser_test_utils.h" +#include "net/base/url_util.h" +#include "net/test/embedded_test_server/http_response.h" +#include "services/network/public/mojom/network_service_test.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { + +namespace browsing_data_browsertest_utils { + +namespace { + +void AddServiceWorkerCallback(bool success) { + ASSERT_TRUE(success); +} + +void GetServiceWorkersCallback( + base::OnceClosure callback, + std::vector<StorageUsageInfo>* out_service_workers, + const std::vector<StorageUsageInfo>& service_workers) { + *out_service_workers = service_workers; + std::move(callback).Run(); +} + +} // namespace + +void ServiceWorkerActivationObserver::SignalActivation( + ServiceWorkerContextWrapper* context, + const base::Closure& callback) { + new ServiceWorkerActivationObserver(context, callback); +} + +ServiceWorkerActivationObserver::ServiceWorkerActivationObserver( + ServiceWorkerContextWrapper* context, + const base::Closure& callback) + : context_(context), scoped_observer_(this), callback_(callback) { + scoped_observer_.Add(context); +} + +ServiceWorkerActivationObserver::~ServiceWorkerActivationObserver() {} + +void ServiceWorkerActivationObserver::OnVersionStateChanged( + int64_t version_id, + const GURL& scope, + ServiceWorkerVersion::Status) { + if (context_->GetLiveVersion(version_id)->status() == + ServiceWorkerVersion::ACTIVATED) { + callback_.Run(); + delete this; + } +} + +void SetIgnoreCertificateErrors(base::CommandLine* command_line) { + if (IsOutOfProcessNetworkService()) { + // |MockCertVerifier| only seems to work when Network Service was enabled. + command_line->AppendSwitch(switches::kUseMockCertVerifierForTesting); + } else { + // We're redirecting all hosts to localhost even on HTTPS, so we'll get + // certificate errors. + command_line->AppendSwitch(switches::kIgnoreCertificateErrors); + } +} + +void AddServiceWorker(const std::string& origin, + StoragePartition* storage_partition, + net::EmbeddedTestServer* https_server) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + ServiceWorkerContextWrapper* service_worker_context = + static_cast<ServiceWorkerContextWrapper*>( + storage_partition->GetServiceWorkerContext()); + + GURL scope_url = https_server->GetURL(origin, "/"); + GURL js_url = https_server->GetURL(origin, "/?file=worker.js"); + + // Register the worker. + blink::mojom::ServiceWorkerRegistrationOptions options( + scope_url, blink::mojom::ScriptType::kClassic, + blink::mojom::ServiceWorkerUpdateViaCache::kImports); + base::PostTask( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&ServiceWorkerContextWrapper::RegisterServiceWorker, + base::Unretained(service_worker_context), js_url, options, + base::Bind(&AddServiceWorkerCallback))); + + // Wait for its activation. + base::RunLoop run_loop; + base::PostTask( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&ServiceWorkerActivationObserver::SignalActivation, + base::Unretained(service_worker_context), + run_loop.QuitClosure())); + run_loop.Run(); +} + +std::vector<StorageUsageInfo> GetServiceWorkers( + StoragePartition* storage_partition) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + ServiceWorkerContextWrapper* service_worker_context = + static_cast<ServiceWorkerContextWrapper*>( + storage_partition->GetServiceWorkerContext()); + + std::vector<StorageUsageInfo> service_workers; + base::RunLoop run_loop; + + base::PostTask( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce( + &ServiceWorkerContextWrapper::GetAllOriginsInfo, + base::Unretained(service_worker_context), + base::Bind(&GetServiceWorkersCallback, run_loop.QuitClosure(), + base::Unretained(&service_workers)))); + run_loop.Run(); + + return service_workers; +} + +void SetResponseContent(const GURL& url, + std::string* value, + net::test_server::BasicHttpResponse* response) { + if (net::GetValueForKeyInQuery(url, "file", value)) { + base::FilePath path(GetTestFilePath("browsing_data", value->c_str())); + base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); + EXPECT_TRUE(file.IsValid()); + int64_t length = file.GetLength(); + EXPECT_GE(length, 0); + std::unique_ptr<char[]> buffer(new char[length + 1]); + file.Read(0, buffer.get(), length); + buffer[length] = '\0'; + + if (path.Extension() == FILE_PATH_LITERAL(".js")) + response->set_content_type("application/javascript"); + else if (path.Extension() == FILE_PATH_LITERAL(".html")) + response->set_content_type("text/html"); + else + NOTREACHED(); + + response->set_content(buffer.get()); + } +} + +void SetUpMockCertVerifier(int32_t default_result) { + network::mojom::NetworkServiceTestPtr network_service_test; + GetSystemConnector()->BindInterface(mojom::kNetworkServiceName, + &network_service_test); + + base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); + network_service_test->MockCertVerifierSetDefaultResult( + default_result, run_loop.QuitClosure()); + run_loop.Run(); +} + +} // namespace browsing_data_browsertest_utils + +} // namespace content
diff --git a/content/browser/browsing_data/browsing_data_browsertest_utils.h b/content/browser/browsing_data/browsing_data_browsertest_utils.h new file mode 100644 index 0000000..4d0669ce --- /dev/null +++ b/content/browser/browsing_data/browsing_data_browsertest_utils.h
@@ -0,0 +1,90 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_BROWSING_DATA_BROWSING_DATA_BROWSERTEST_UTILS_H_ +#define CONTENT_BROWSER_BROWSING_DATA_BROWSING_DATA_BROWSERTEST_UTILS_H_ + +#include <string> +#include <vector> + +#include "base/scoped_observer.h" +#include "content/browser/service_worker/service_worker_context_core_observer.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_response.h" +#include "services/network/public/mojom/cookie_manager.mojom.h" + +namespace content { +class StoragePartition; + +namespace browsing_data_browsertest_utils { + +// TODO(msramek): A class like this already exists in ServiceWorkerBrowserTest. +// Consider extracting it to a different test utils file. +class ServiceWorkerActivationObserver + : public ServiceWorkerContextCoreObserver { + public: + // |callback| is called when |context| is activated. + static void SignalActivation(ServiceWorkerContextWrapper* context, + const base::Closure& callback); + + private: + ServiceWorkerActivationObserver(ServiceWorkerContextWrapper* context, + const base::Closure& callback); + + ~ServiceWorkerActivationObserver() override; + + // ServiceWorkerContextCoreObserver overrides. + void OnVersionStateChanged(int64_t version_id, + const GURL& scope, + ServiceWorkerVersion::Status) override; + + ServiceWorkerContextWrapper* context_; + ScopedObserver<ServiceWorkerContextWrapper, ServiceWorkerContextCoreObserver> + scoped_observer_; + base::Closure callback_; +}; + +// Appends a switch to the |command_line| based on whether the network service +// is enabled. The browser will ignore certificate errors if the network service +// is not enabled. +void SetIgnoreCertificateErrors(base::CommandLine* command_line); + +// Adds a service worker for the given |origin|. The EmbeddedTestServer +// |https_server| is required to retrieve a URL to the server based on the +// |origin|. +void AddServiceWorker(const std::string& origin, + StoragePartition* storage_partition, + net::EmbeddedTestServer* https_server); + +// Retrieves the list of all service workers. +std::vector<StorageUsageInfo> GetServiceWorkers( + StoragePartition* storage_partition); + +// Populates the content and content type fields of a given HTTP |response| +// based on the file extension of the |url| as follows: +// +// For .js: +// Example: "https://localhost/?file=file.js" +// will set the response header as +// Content-Type: application/javascript +// +// For .html: +// Example: "https://localhost/?file=file.html" +// will set the response header as +// Content-Type: text/html +// +// Response content type is only set for .js and .html files. +void SetResponseContent(const GURL& url, + std::string* value, + net::test_server::BasicHttpResponse* response); + +// Sets up a MockCertVerifier with default return value |default_result|. +void SetUpMockCertVerifier(int32_t default_result); + +} // namespace browsing_data_browsertest_utils + +} // namespace content + +#endif // CONTENT_BROWSER_BROWSING_DATA_BROWSING_DATA_BROWSERTEST_UTILS_H_
diff --git a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc index f2bef53..100c149 100644 --- a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc +++ b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
@@ -14,15 +14,12 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" -#include "base/task/post_task.h" #include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" #include "base/thread_annotations.h" #include "build/build_config.h" -#include "components/network_session_configurator/common/network_switches.h" +#include "content/browser/browsing_data/browsing_data_browsertest_utils.h" #include "content/browser/browsing_data/browsing_data_filter_builder_impl.h" -#include "content/browser/service_worker/service_worker_context_core_observer.h" -#include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -30,12 +27,8 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_usage_info.h" -#include "content/public/browser/system_connector.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/content_switches.h" #include "content/public/common/network_service_util.h" -#include "content/public/common/service_names.mojom.h" -#include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/mock_browsing_data_remover_delegate.h" @@ -50,7 +43,6 @@ #include "net/test/embedded_test_server/http_response.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" -#include "services/network/public/mojom/network_service_test.mojom.h" #include "services/service_manager/public/cpp/connector.h" #include "storage/browser/quota/quota_settings.h" #include "testing/gmock/include/gmock/gmock.h" @@ -129,57 +121,13 @@ } }; -// TODO(msramek): A class like this already exists in ServiceWorkerBrowserTest. -// Consider extracting it to a test utils file. -class ServiceWorkerActivationObserver - : public ServiceWorkerContextCoreObserver { - public: - static void SignalActivation(ServiceWorkerContextWrapper* context, - const base::Closure& callback) { - new ServiceWorkerActivationObserver(context, callback); - } - - private: - ServiceWorkerActivationObserver(ServiceWorkerContextWrapper* context, - const base::Closure& callback) - : context_(context), scoped_observer_(this), callback_(callback) { - scoped_observer_.Add(context); - } - - ~ServiceWorkerActivationObserver() override {} - - // ServiceWorkerContextCoreObserver overrides. - void OnVersionStateChanged(int64_t version_id, - const GURL& scope, - ServiceWorkerVersion::Status) override { - if (context_->GetLiveVersion(version_id)->status() == - ServiceWorkerVersion::ACTIVATED) { - callback_.Run(); - delete this; - } - } - - ServiceWorkerContextWrapper* context_; - ScopedObserver<ServiceWorkerContextWrapper, ServiceWorkerContextCoreObserver> - scoped_observer_; - base::Closure callback_; -}; - } // namespace class ClearSiteDataHandlerBrowserTest : public ContentBrowserTest { public: void SetUpCommandLine(base::CommandLine* command_line) override { ContentBrowserTest::SetUpCommandLine(command_line); - - if (IsOutOfProcessNetworkService()) { - // |MockCertVerifier| only seems to work when Network Service was enabled. - command_line->AppendSwitch(switches::kUseMockCertVerifierForTesting); - } else { - // We're redirecting all hosts to localhost even on HTTPS, so we'll get - // certificate errors. - command_line->AppendSwitch(switches::kIgnoreCertificateErrors); - } + browsing_data_browsertest_utils::SetIgnoreCertificateErrors(command_line); } void SetUpOnMainThread() override { @@ -192,7 +140,7 @@ host_resolver()->AddRule("*", "127.0.0.1"); if (IsOutOfProcessNetworkService()) - SetUpMockCertVerifier(net::OK); + browsing_data_browsertest_utils::SetUpMockCertVerifier(net::OK); embedded_test_server()->RegisterRequestHandler( base::BindRepeating(&ClearSiteDataHandlerBrowserTest::HandleRequest, @@ -248,64 +196,6 @@ return cookie_list; } - // Adds a service worker. Used in the storage integration tests. - void AddServiceWorker(const std::string& origin) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - ServiceWorkerContextWrapper* service_worker_context = - static_cast<ServiceWorkerContextWrapper*>( - storage_partition()->GetServiceWorkerContext()); - - GURL scope_url = https_server()->GetURL(origin, "/"); - GURL js_url = https_server()->GetURL(origin, "/?file=worker.js"); - - // Register the worker. - blink::mojom::ServiceWorkerRegistrationOptions options( - scope_url, blink::mojom::ScriptType::kClassic, - blink::mojom::ServiceWorkerUpdateViaCache::kImports); - RunOrPostTaskOnThread( - FROM_HERE, ServiceWorkerContext::GetCoreThreadId(), - base::BindOnce( - &ServiceWorkerContextWrapper::RegisterServiceWorker, - base::Unretained(service_worker_context), js_url, options, - base::Bind( - &ClearSiteDataHandlerBrowserTest::AddServiceWorkerCallback, - base::Unretained(this)))); - - // Wait for its activation. - base::RunLoop run_loop; - RunOrPostTaskOnThread( - FROM_HERE, ServiceWorkerContext::GetCoreThreadId(), - base::BindOnce(&ServiceWorkerActivationObserver::SignalActivation, - base::Unretained(service_worker_context), - run_loop.QuitClosure())); - run_loop.Run(); - } - - // Retrieves the list of all service workers. Used in the storage integration - // tests. - std::vector<StorageUsageInfo> GetServiceWorkers() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - ServiceWorkerContextWrapper* service_worker_context = - static_cast<ServiceWorkerContextWrapper*>( - storage_partition()->GetServiceWorkerContext()); - - std::vector<StorageUsageInfo> service_workers; - base::RunLoop run_loop; - - RunOrPostTaskOnThread( - FROM_HERE, ServiceWorkerContext::GetCoreThreadId(), - base::BindOnce( - &ServiceWorkerContextWrapper::GetAllOriginsInfo, - base::Unretained(service_worker_context), - base::Bind( - &ClearSiteDataHandlerBrowserTest::GetServiceWorkersCallback, - base::Unretained(this), run_loop.QuitClosure(), - base::Unretained(&service_workers)))); - run_loop.Run(); - - return service_workers; - } - void CreateCacheEntry(const GURL& url) { ASSERT_EQ(net::OK, LoadBasicRequest(storage_partition()->GetNetworkContext(), url)); @@ -392,27 +282,15 @@ if (net::GetValueForKeyInQuery(request.GetURL(), "html", &value)) { response->set_content_type("text/html"); response->set_content(value); + + // The "html" parameter is telling the server what to serve, and the XSS + // auditor will complain if its |value| contains JS code. Disable that + // protection. + response->AddCustomHeader("X-XSS-Protection", "0"); } - if (net::GetValueForKeyInQuery(request.GetURL(), "file", &value)) { - base::FilePath path(GetTestFilePath("browsing_data", value.c_str())); - base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); - EXPECT_TRUE(file.IsValid()); - int64_t length = file.GetLength(); - EXPECT_GE(length, 0); - std::unique_ptr<char[]> buffer(new char[length + 1]); - file.Read(0, buffer.get(), length); - buffer[length] = '\0'; - - if (path.Extension() == FILE_PATH_LITERAL(".js")) - response->set_content_type("application/javascript"); - else if (path.Extension() == FILE_PATH_LITERAL(".html")) - response->set_content_type("text/html"); - else - NOTREACHED(); - - response->set_content(buffer.get()); - } + browsing_data_browsertest_utils::SetResponseContent(request.GetURL(), + &value, response.get()); if (base::StartsWith(request.relative_url, "/cachetime", base::CompareCase::SENSITIVE)) { @@ -425,17 +303,6 @@ return std::move(response); } - void SetUpMockCertVerifier(int32_t default_result) { - network::mojom::NetworkServiceTestPtr network_service_test; - GetSystemConnector()->BindInterface(mojom::kNetworkServiceName, - &network_service_test); - - base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); - network_service_test->MockCertVerifierSetDefaultResult( - default_result, run_loop.QuitClosure()); - run_loop.Run(); - } - // Callback handler for AddCookie(). static void AddCookieCallback( base::OnceClosure callback, @@ -454,18 +321,6 @@ std::move(callback).Run(); } - // Callback handler for AddServiceWorker(). - void AddServiceWorkerCallback(bool success) { ASSERT_TRUE(success); } - - // Callback handler for GetServiceWorkers(). - void GetServiceWorkersCallback( - base::OnceClosure callback, - std::vector<StorageUsageInfo>* out_service_workers, - const std::vector<StorageUsageInfo>& service_workers) { - *out_service_workers = service_workers; - std::move(callback).Run(); - } - // If this is set, |HandleRequest| will always respond with Clear-Site-Data. base::Lock clear_site_data_header_lock_; std::string clear_site_data_header_ GUARDED_BY(clear_site_data_header_lock_); @@ -885,36 +740,44 @@ // Integration test for the unregistering of service workers. IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest, StorageServiceWorkersIntegrationTest) { - AddServiceWorker("origin1.com"); - AddServiceWorker("origin2.com"); + StoragePartition* partition = storage_partition(); + net::EmbeddedTestServer* server = https_server(); + + browsing_data_browsertest_utils::AddServiceWorker("origin1.com", partition, + server); + browsing_data_browsertest_utils::AddServiceWorker("origin2.com", partition, + server); // There are two service workers installed on two origins. - std::vector<StorageUsageInfo> service_workers = GetServiceWorkers(); + std::vector<StorageUsageInfo> service_workers = + browsing_data_browsertest_utils::GetServiceWorkers(partition); EXPECT_EQ(2u, service_workers.size()); // Navigate to a URL within the scope of "origin1.com" which responds with // a Clear-Site-Data header. Verify that this did NOT remove the service // worker for "origin1.com", as the header would not be respected outside // of the scope. - GURL url = https_server()->GetURL("origin1.com", "/anything-in-the-scope"); + GURL url = server->GetURL("origin1.com", "/anything-in-the-scope"); AddQuery(&url, "header", "\"storage\""); NavigateToURL(shell(), url); - service_workers = GetServiceWorkers(); + service_workers = + browsing_data_browsertest_utils::GetServiceWorkers(partition); EXPECT_EQ(2u, service_workers.size()); // This time, we will navigate to a URL on "origin1.com" that is not handled // by the serice worker, but results in a network request. One such resource // not handled by "worker.js" is the path "resource". // The header will be respected and the worker deleted. - url = https_server()->GetURL("origin1.com", "/resource"); + url = server->GetURL("origin1.com", "/resource"); AddQuery(&url, "header", "\"storage\""); NavigateToURL(shell(), url); // Only "origin2.com" now has a service worker. - service_workers = GetServiceWorkers(); + service_workers = + browsing_data_browsertest_utils::GetServiceWorkers(partition); ASSERT_EQ(1u, service_workers.size()); EXPECT_EQ(service_workers[0].origin.GetURL(), - https_server()->GetURL("origin2.com", "/")); + server->GetURL("origin2.com", "/")); // TODO(msramek): Test that the service worker update ping also deletes // the service worker.
diff --git a/content/browser/browsing_data/same_site_data_remover_impl_browsertest.cc b/content/browser/browsing_data/same_site_data_remover_impl_browsertest.cc index 3f539900..39d23fa6 100644 --- a/content/browser/browsing_data/same_site_data_remover_impl_browsertest.cc +++ b/content/browser/browsing_data/same_site_data_remover_impl_browsertest.cc
@@ -9,30 +9,18 @@ #include <vector> #include "base/bind.h" -#include "base/command_line.h" #include "base/run_loop.h" -#include "base/scoped_observer.h" -#include "base/task/post_task.h" -#include "components/network_session_configurator/common/network_switches.h" +#include "content/browser/browsing_data/browsing_data_browsertest_utils.h" #include "content/browser/browsing_data/browsing_data_test_utils.h" -#include "content/browser/service_worker/service_worker_context_wrapper.h" -#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/same_site_data_remover.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_usage_info.h" -#include "content/public/browser/system_connector.h" -#include "content/public/common/content_switches.h" #include "content/public/common/network_service_util.h" -#include "content/public/common/service_names.mojom.h" #include "content/public/test/content_browser_test.h" -#include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" -#include "net/base/url_util.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" -#include "services/network/public/mojom/cookie_manager.mojom.h" -#include "services/network/public/mojom/network_service_test.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -40,44 +28,6 @@ namespace content { -namespace { - -class ServiceWorkerActivationObserver - : public ServiceWorkerContextCoreObserver { - public: - static void SignalActivation(ServiceWorkerContextWrapper* context, - const base::Closure& callback) { - new ServiceWorkerActivationObserver(context, callback); - } - - private: - ServiceWorkerActivationObserver(ServiceWorkerContextWrapper* context, - const base::Closure& callback) - : context_(context), scoped_observer_(this), callback_(callback) { - scoped_observer_.Add(context); - } - - ~ServiceWorkerActivationObserver() override {} - - // ServiceWorkerContextCoreObserver overrides. - void OnVersionStateChanged(int64_t version_id, - const GURL& scope, - ServiceWorkerVersion::Status) override { - if (context_->GetLiveVersion(version_id)->status() == - ServiceWorkerVersion::ACTIVATED) { - callback_.Run(); - delete this; - } - } - - ServiceWorkerContextWrapper* context_; - ScopedObserver<ServiceWorkerContextWrapper, ServiceWorkerContextCoreObserver> - scoped_observer_; - base::Closure callback_; -}; - -} // namespace - class SameSiteDataRemoverBrowserTest : public ContentBrowserTest { public: SameSiteDataRemoverBrowserTest() {} @@ -89,7 +39,7 @@ host_resolver()->AddRule("*", "127.0.0.1"); if (IsOutOfProcessNetworkService()) - SetUpMockCertVerifier(net::OK); + browsing_data_browsertest_utils::SetUpMockCertVerifier(net::OK); https_server_.reset(new net::EmbeddedTestServer( net::test_server::EmbeddedTestServer::TYPE_HTTPS)); @@ -102,92 +52,19 @@ void SetUpCommandLine(base::CommandLine* command_line) override { ContentBrowserTest::SetUpCommandLine(command_line); - - if (IsOutOfProcessNetworkService()) { - // |MockCertVerifier| only seems to work when Network Service was enabled. - command_line->AppendSwitch(switches::kUseMockCertVerifierForTesting); - } else { - // We're redirecting all hosts to localhost even on HTTPS, so we'll get - // certificate errors. - command_line->AppendSwitch(switches::kIgnoreCertificateErrors); - } + browsing_data_browsertest_utils::SetIgnoreCertificateErrors(command_line); } BrowserContext* GetBrowserContext() { return shell()->web_contents()->GetBrowserContext(); } + StoragePartition* GetStoragePartition() { + return BrowserContext::GetDefaultStoragePartition(GetBrowserContext()); + } + net::EmbeddedTestServer* GetHttpsServer() { return https_server_.get(); } - void SetUpMockCertVerifier(int32_t default_result) { - network::mojom::NetworkServiceTestPtr network_service_test; - GetSystemConnector()->BindInterface(mojom::kNetworkServiceName, - &network_service_test); - - base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); - network_service_test->MockCertVerifierSetDefaultResult( - default_result, run_loop.QuitClosure()); - run_loop.Run(); - } - - void AddServiceWorker(const std::string& origin) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - StoragePartition* partition = - BrowserContext::GetDefaultStoragePartition(GetBrowserContext()); - ServiceWorkerContextWrapper* service_worker_context = - static_cast<ServiceWorkerContextWrapper*>( - partition->GetServiceWorkerContext()); - - GURL scope_url = GetHttpsServer()->GetURL(origin, "/"); - GURL js_url = GetHttpsServer()->GetURL(origin, "/?file=worker.js"); - - // Register the worker. - blink::mojom::ServiceWorkerRegistrationOptions options( - scope_url, blink::mojom::ScriptType::kClassic, - blink::mojom::ServiceWorkerUpdateViaCache::kImports); - RunOrPostTaskOnThread( - FROM_HERE, ServiceWorkerContext::GetCoreThreadId(), - base::BindOnce( - &ServiceWorkerContextWrapper::RegisterServiceWorker, - base::Unretained(service_worker_context), js_url, options, - base::Bind( - &SameSiteDataRemoverBrowserTest::AddServiceWorkerCallback, - base::Unretained(this)))); - - // Wait for its activation. - base::RunLoop run_loop; - RunOrPostTaskOnThread( - FROM_HERE, ServiceWorkerContext::GetCoreThreadId(), - base::BindOnce(&ServiceWorkerActivationObserver::SignalActivation, - base::Unretained(service_worker_context), - run_loop.QuitClosure())); - run_loop.Run(); - } - - std::vector<StorageUsageInfo> GetServiceWorkers() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - StoragePartition* partition = - BrowserContext::GetDefaultStoragePartition(GetBrowserContext()); - ServiceWorkerContextWrapper* service_worker_context = - static_cast<ServiceWorkerContextWrapper*>( - partition->GetServiceWorkerContext()); - - std::vector<StorageUsageInfo> service_workers; - base::RunLoop run_loop; - RunOrPostTaskOnThread( - FROM_HERE, ServiceWorkerContext::GetCoreThreadId(), - base::BindOnce( - &ServiceWorkerContextWrapper::GetAllOriginsInfo, - base::Unretained(service_worker_context), - base::Bind( - &SameSiteDataRemoverBrowserTest::GetServiceWorkersCallback, - base::Unretained(this), run_loop.QuitClosure(), - base::Unretained(&service_workers)))); - run_loop.Run(); - - return service_workers; - } - void ClearData(bool clear_storage) { base::RunLoop run_loop; ClearSameSiteNoneData(run_loop.QuitClosure(), GetBrowserContext(), @@ -196,16 +73,6 @@ } private: - void AddServiceWorkerCallback(bool success) { ASSERT_TRUE(success); } - - void GetServiceWorkersCallback( - base::OnceClosure callback, - std::vector<StorageUsageInfo>* out_service_workers, - const std::vector<StorageUsageInfo>& service_workers) { - *out_service_workers = service_workers; - std::move(callback).Run(); - } - // Handles all requests. // // Supports the following <key>=<value> query parameters in the url: @@ -215,23 +82,8 @@ auto response(std::make_unique<net::test_server::BasicHttpResponse>()); std::string value; - if (net::GetValueForKeyInQuery(request.GetURL(), "file", &value)) { - base::FilePath path(GetTestFilePath("browsing_data", value.c_str())); - base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); - EXPECT_TRUE(file.IsValid()); - int64_t length = file.GetLength(); - EXPECT_GE(length, 0); - std::unique_ptr<char[]> buffer(new char[length + 1]); - file.Read(0, buffer.get(), length); - buffer[length] = '\0'; - - if (path.Extension() == FILE_PATH_LITERAL(".js")) - response->set_content_type("application/javascript"); - else - NOTREACHED(); - - response->set_content(buffer.get()); - } + browsing_data_browsertest_utils::SetResponseContent(request.GetURL(), + &value, response.get()); return std::move(response); } @@ -243,11 +95,13 @@ IN_PROC_BROWSER_TEST_F(SameSiteDataRemoverBrowserTest, TestClearDataWithStorageRemoval) { + StoragePartition* storage_partition = GetStoragePartition(); CreateCookieForTest("TestCookie", "www.google.com", net::CookieSameSite::NO_RESTRICTION, net::CookieOptions::SameSiteCookieContext::CROSS_SITE, GetBrowserContext()); - AddServiceWorker("www.google.com"); + browsing_data_browsertest_utils::AddServiceWorker( + "www.google.com", storage_partition, GetHttpsServer()); ClearData(/* clear_storage= */ true); @@ -257,17 +111,20 @@ EXPECT_THAT(cookies, IsEmpty()); // Check that the service worker for the cookie domain was removed. - std::vector<StorageUsageInfo> service_workers = GetServiceWorkers(); + std::vector<StorageUsageInfo> service_workers = + browsing_data_browsertest_utils::GetServiceWorkers(storage_partition); EXPECT_THAT(service_workers, IsEmpty()); } IN_PROC_BROWSER_TEST_F(SameSiteDataRemoverBrowserTest, TestClearDataWithoutStorageRemoval) { + StoragePartition* storage_partition = GetStoragePartition(); CreateCookieForTest("TestCookie", "www.google.com", net::CookieSameSite::NO_RESTRICTION, net::CookieOptions::SameSiteCookieContext::CROSS_SITE, GetBrowserContext()); - AddServiceWorker("www.google.com"); + browsing_data_browsertest_utils::AddServiceWorker( + "www.google.com", storage_partition, GetHttpsServer()); ClearData(/* clear_storage= */ false); @@ -277,7 +134,8 @@ EXPECT_THAT(cookies, IsEmpty()); // Storage partition data should NOT have been cleared. - std::vector<StorageUsageInfo> service_workers = GetServiceWorkers(); + std::vector<StorageUsageInfo> service_workers = + browsing_data_browsertest_utils::GetServiceWorkers(storage_partition); ASSERT_EQ(1u, service_workers.size()); EXPECT_EQ(service_workers[0].origin.GetURL(), GetHttpsServer()->GetURL("www.google.com", "/"));
diff --git a/content/browser/child_process_launcher_helper_fuchsia.cc b/content/browser/child_process_launcher_helper_fuchsia.cc index ea9bef7..204ff17 100644 --- a/content/browser/child_process_launcher_helper_fuchsia.cc +++ b/content/browser/child_process_launcher_helper_fuchsia.cc
@@ -6,14 +6,41 @@ #include "base/command_line.h" #include "base/process/launch.h" +#include "base/strings/stringprintf.h" #include "content/browser/child_process_launcher.h" #include "content/public/browser/child_process_launcher_utils.h" #include "content/public/common/sandboxed_process_launcher_delegate.h" #include "services/service_manager/embedder/result_codes.h" +#include "services/service_manager/embedder/switches.h" namespace content { namespace internal { +namespace { + +const char* ProcessNameFromSandboxType( + service_manager::SandboxType sandbox_type) { + switch (sandbox_type) { + case service_manager::SANDBOX_TYPE_NO_SANDBOX: + return nullptr; + case service_manager::SANDBOX_TYPE_WEB_CONTEXT: + return "context"; + case service_manager::SANDBOX_TYPE_RENDERER: + return "renderer"; + case service_manager::SANDBOX_TYPE_UTILITY: + return "utility"; + case service_manager::SANDBOX_TYPE_GPU: + return "gpu"; + case service_manager::SANDBOX_TYPE_NETWORK: + return "network"; + default: + NOTREACHED() << sandbox_type; + return nullptr; + } +} + +} // namespace + void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread( base::Process process, const ChildProcessLauncherPriority& priority) { @@ -68,6 +95,12 @@ command_line()); sandbox_policy_.UpdateLaunchOptionsForSandbox(options); + // Set process name suffix to make it easier to identify the process. + const char* process_type = + ProcessNameFromSandboxType(delegate_->GetSandboxType()); + if (process_type) + options->process_name_suffix = base::StringPrintf(":%s", process_type); + return true; }
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc index 648b1cda..19b3c788 100644 --- a/content/browser/frame_host/navigation_controller_impl_unittest.cc +++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -2450,7 +2450,6 @@ std::string(), browser_context(), nullptr /* blob_url_loader_factory */); entry->SetTitle(base::ASCIIToUTF16("Title")); - entry->SetPageState(PageState::CreateFromEncodedData("state")); const base::Time timestamp = base::Time::Now(); entry->SetTimestamp(timestamp); entries.push_back(std::move(entry)); @@ -2519,7 +2518,6 @@ std::string(), browser_context(), nullptr /* blob_url_loader_factory */); new_entry->SetTitle(base::ASCIIToUTF16("Title")); - new_entry->SetPageState(PageState::CreateFromEncodedData("state")); entries.push_back(std::move(new_entry)); std::unique_ptr<WebContents> our_contents = WebContents::Create(WebContents::CreateParams(browser_context()));
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc index 96903525c..275a9da 100644 --- a/content/browser/frame_host/navigation_entry_impl.cc +++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -95,6 +95,12 @@ } } +base::Optional<base::string16> UrlToOptionalString16(const GURL& url) { + if (!url.is_valid()) + return base::nullopt; + return base::UTF8ToUTF16(url.spec()); +} + void RecursivelyGenerateFrameState( NavigationEntryImpl::TreeNode* node, ExplodedFrameState* state, @@ -112,6 +118,35 @@ // Copy the FrameNavigationEntry's frame state into the destination state. *state = frame_state; + // Some data is stored *both* in 1) PageState/ExplodedFrameState and 2) + // FrameNavigationEntry. We want to treat FrameNavigationEntry as the + // authoritative source of the data, so we clobber the ExplodedFrameState with + // the data taken from FrameNavigationEntry. + // + // The following ExplodedFrameState fields do not have an equivalent + // FrameNavigationEntry field: + // - target + // - state_object + // - document_state + // - scroll_restoration_type + // - did_save_scroll_or_scale_state + // - visual_viewport_scroll_offset + // - scroll_offset + // - page_scale_factor + // - http_body (FrameNavigationEntry::GetPostData extracts the body from + // the ExplodedFrameState) + // - scroll_anchor_selector + // - scroll_anchor_offset + // - scroll_anchor_simhash + state->url_string = UrlToOptionalString16(node->frame_entry->url()); + state->referrer = UrlToOptionalString16(node->frame_entry->referrer().url); + state->referrer_policy = node->frame_entry->referrer().policy; + state->item_sequence_number = node->frame_entry->item_sequence_number(); + state->document_sequence_number = + node->frame_entry->document_sequence_number(); + // TODO(lukasza): https://crbug.com/976055: Persist |initiator_origin| in + // the ExplodedFrameState. + // Copy the frame's files into the PageState's |referenced_files|. referenced_files->reserve(referenced_files->size() + exploded_page_state.referenced_files.size()); @@ -386,12 +421,10 @@ if (!frame_tree_->children.empty()) frame_tree_->children.clear(); - // If the PageState can't be parsed or has no children, just store it on the - // main frame's FrameNavigationEntry without recursively creating subframe - // entries. + // If the PageState can't be parsed, just store it on the main frame's + // FrameNavigationEntry without recursively creating subframe entries. ExplodedPageState exploded_state; - if (!DecodePageState(state.ToEncodedData(), &exploded_state) || - exploded_state.top.children.size() == 0U) { + if (!DecodePageState(state.ToEncodedData(), &exploded_state)) { frame_tree_->frame_entry->SetPageState(state); return; } @@ -401,14 +434,8 @@ } PageState NavigationEntryImpl::GetPageState() { - // Just return the main frame's state if there are no subframe - // FrameNavigationEntries. - if (frame_tree_->children.size() == 0U) - return frame_tree_->frame_entry->page_state(); - - // When we're using subframe entries, each FrameNavigationEntry has a - // frame-specific PageState. We combine these into an ExplodedPageState tree - // and generate a full PageState from it. + // Each FrameNavigationEntry has a frame-specific PageState. We combine these + // into an ExplodedPageState tree and generate a full PageState from it. ExplodedPageState exploded_state; RecursivelyGenerateFrameState(frame_tree_.get(), &exploded_state.top, &exploded_state.referenced_files);
diff --git a/content/browser/frame_host/navigation_entry_impl_unittest.cc b/content/browser/frame_host/navigation_entry_impl_unittest.cc index 9bbcf168..45cb8cd6 100644 --- a/content/browser/frame_host/navigation_entry_impl_unittest.cc +++ b/content/browser/frame_host/navigation_entry_impl_unittest.cc
@@ -14,6 +14,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "content/browser/site_instance_impl.h" +#include "content/common/page_state_serialization.h" #include "content/public/browser/ssl_status.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_browser_context.h" @@ -49,6 +50,13 @@ DISALLOW_COPY_AND_ASSIGN(TestSSLStatusData); }; +PageState CreateTestPageState() { + ExplodedPageState exploded_state; + std::string encoded_data; + EncodePageState(exploded_state, &encoded_data); + return PageState::CreateFromEncodedData(encoded_data); +} + } // namespace class NavigationEntryTest : public testing::Test { @@ -231,12 +239,6 @@ entry2_->SetTitle(ASCIIToUTF16("title2")); EXPECT_EQ(ASCIIToUTF16("title2"), entry2_->GetTitle()); - // State - EXPECT_FALSE(entry1_->GetPageState().IsValid()); - EXPECT_FALSE(entry2_->GetPageState().IsValid()); - entry2_->SetPageState(PageState::CreateFromEncodedData("state")); - EXPECT_EQ("state", entry2_->GetPageState().ToEncodedData()); - // Transition type EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs( entry1_->GetTransitionType(), ui::PAGE_TRANSITION_LINK)); @@ -292,10 +294,21 @@ // Initiator origin. EXPECT_FALSE( entry1_->root_node()->frame_entry->initiator_origin().has_value()); - EXPECT_TRUE( + ASSERT_TRUE( entry2_->root_node()->frame_entry->initiator_origin().has_value()); EXPECT_EQ(url::Origin::Create(GURL("https://initiator.example.com")), entry2_->root_node()->frame_entry->initiator_origin().value()); + + // State. + // + // Note that calling SetPageState may also set some other FNE members + // (referrer, initiator, etc.). This is why it is important to test + // SetPageState/GetPageState last. + PageState test_page_state = CreateTestPageState(); + entry2_->SetPageState(test_page_state); + // TODO(lukasza): https://crbug.com/976055: Once |initiator_origin| is + // persisted across session restore, the test here should verify that + // SetPageState round-trips via GetPageState. } // Test basic Clone behavior.
diff --git a/content/browser/frame_host/render_frame_message_filter_browsertest.cc b/content/browser/frame_host/render_frame_message_filter_browsertest.cc index 1b38667..b06c83b 100644 --- a/content/browser/frame_host/render_frame_message_filter_browsertest.cc +++ b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
@@ -295,7 +295,7 @@ public: RestrictedCookieManagerInterceptor( mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver, - network::mojom::RestrictedCookieManagerPtr real_rcm) + mojo::PendingRemote<network::mojom::RestrictedCookieManager> real_rcm) : receiver_(this, std::move(receiver)), real_rcm_(std::move(real_rcm)) {} void set_override_url(base::Optional<std::string> maybe_url) { @@ -332,7 +332,7 @@ base::Optional<std::string> override_url_; mojo::Receiver<network::mojom::RestrictedCookieManager> receiver_; - network::mojom::RestrictedCookieManagerPtr real_rcm_; + mojo::Remote<network::mojom::RestrictedCookieManager> real_rcm_; }; class CookieStoreContentBrowserClient : public ContentBrowserClient { @@ -351,8 +351,8 @@ mojo::PendingReceiver<network::mojom::RestrictedCookieManager> orig_receiver = std::move(*receiver); - network::mojom::RestrictedCookieManagerPtr real_rcm; - *receiver = mojo::MakeRequest(&real_rcm); + mojo::PendingRemote<network::mojom::RestrictedCookieManager> real_rcm; + *receiver = real_rcm.InitWithNewPipeAndPassReceiver(); rcm_interceptor_ = std::make_unique<RestrictedCookieManagerInterceptor>( std::move(orig_receiver), std::move(real_rcm));
diff --git a/content/browser/media/android/media_resource_getter_impl.cc b/content/browser/media/android/media_resource_getter_impl.cc index 066a634..64f2255 100644 --- a/content/browser/media/android/media_resource_getter_impl.cc +++ b/content/browser/media/android/media_resource_getter_impl.cc
@@ -19,6 +19,7 @@ #include "content/public/common/content_client.h" #include "content/public/common/url_constants.h" #include "media/base/android/media_url_interceptor.h" +#include "mojo/public/cpp/bindings/remote.h" #include "net/base/auth.h" #include "net/http/http_auth.h" #include "services/network/public/mojom/restricted_cookie_manager.mojom.h" @@ -32,24 +33,22 @@ // Returns the cookie manager for the |browser_context| at the client end of the // mojo pipe. This will be restricted to the origin of |url|, and will apply // policies from user and ContentBrowserClient to cookie operations. -network::mojom::RestrictedCookieManagerPtr GetRestrictedCookieManagerForContext( - BrowserContext* browser_context, - const GURL& url, - int render_process_id, - int render_frame_id) { +mojo::PendingRemote<network::mojom::RestrictedCookieManager> +GetRestrictedCookieManagerForContext(BrowserContext* browser_context, + const GURL& url, + int render_process_id, + int render_frame_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); url::Origin origin = url::Origin::Create(url); StoragePartition* storage_partition = BrowserContext::GetDefaultStoragePartition(browser_context); - network::mojom::RestrictedCookieManagerPtr pipe; - mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver = - mojo::MakeRequest(&pipe); + mojo::PendingRemote<network::mojom::RestrictedCookieManager> pipe; storage_partition->CreateRestrictedCookieManager( network::mojom::RestrictedCookieManagerRole::NETWORK, origin, /* is_service_worker = */ false, render_process_id, render_frame_id, - std::move(receiver)); + pipe.InitWithNewPipeAndPassReceiver()); return pipe; } @@ -61,7 +60,7 @@ } void ReturnResultOnUIThreadAndClosePipe( - network::mojom::RestrictedCookieManagerPtr pipe, + mojo::Remote<network::mojom::RestrictedCookieManager> pipe, base::OnceCallback<void(const std::string&)> callback, const std::string& result) { base::PostTask(FROM_HERE, {BrowserThread::UI}, @@ -143,9 +142,9 @@ return; } - network::mojom::RestrictedCookieManagerPtr cookie_manager = + mojo::Remote<network::mojom::RestrictedCookieManager> cookie_manager( GetRestrictedCookieManagerForContext( - browser_context_, url, render_process_id_, render_frame_id_); + browser_context_, url, render_process_id_, render_frame_id_)); network::mojom::RestrictedCookieManager* cookie_manager_ptr = cookie_manager.get(); cookie_manager_ptr->GetCookiesString(
diff --git a/content/browser/picture_in_picture/picture_in_picture_service_impl.cc b/content/browser/picture_in_picture/picture_in_picture_service_impl.cc index f465e90..b37eb213 100644 --- a/content/browser/picture_in_picture/picture_in_picture_service_impl.cc +++ b/content/browser/picture_in_picture/picture_in_picture_service_impl.cc
@@ -42,7 +42,6 @@ const base::Optional<viz::SurfaceId>& surface_id, const gfx::Size& natural_size, bool show_play_pause_button, - bool show_mute_button, mojo::PendingRemote<blink::mojom::PictureInPictureSessionObserver> observer, StartSessionCallback callback) { gfx::Size window_size; @@ -60,7 +59,7 @@ if (result == PictureInPictureResult::kSuccess) { active_session_ = std::make_unique<PictureInPictureSession>( this, MediaPlayerId(render_frame_host_, player_id), surface_id, - natural_size, show_play_pause_button, show_mute_button, + natural_size, show_play_pause_button, session_remote.InitWithNewPipeAndPassReceiver(), std::move(observer), &window_size); }
diff --git a/content/browser/picture_in_picture/picture_in_picture_service_impl.h b/content/browser/picture_in_picture/picture_in_picture_service_impl.h index cfa35d1..96f796c 100644 --- a/content/browser/picture_in_picture/picture_in_picture_service_impl.h +++ b/content/browser/picture_in_picture/picture_in_picture_service_impl.h
@@ -45,7 +45,6 @@ const base::Optional<viz::SurfaceId>& surface_id, const gfx::Size& natural_size, bool show_play_pause_button, - bool show_mute_button, mojo::PendingRemote<blink::mojom::PictureInPictureSessionObserver>, StartSessionCallback) final;
diff --git a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc index b0b4520..ce37baa 100644 --- a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc +++ b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
@@ -72,7 +72,6 @@ } void SetPlaybackState(PlaybackState playback_state) override {} void SetAlwaysHidePlayPauseButton(bool is_visible) override {} - void SetMutedState(MutedState muted_state) override {} void SetSkipAdButtonVisibility(bool is_visible) override {} void SetNextTrackButtonVisibility(bool is_visible) override {} void SetPreviousTrackButtonVisibility(bool is_visible) override {} @@ -162,8 +161,7 @@ service().StartSession( kPlayerVideoOnlyId, surface_id, gfx::Size(42, 42), - true /* show_play_pause_button */, true /* show_mute_button */, - std::move(observer_remote), + true /* show_play_pause_button */, std::move(observer_remote), base::BindLambdaForTesting( [&](mojo::PendingRemote<blink::mojom::PictureInPictureSession> remote, const gfx::Size& b) { @@ -205,8 +203,7 @@ service().StartSession( kPlayerVideoOnlyId, surface_id, gfx::Size(42, 42), - true /* show_play_pause_button */, true /* show_mute_button */, - std::move(observer_remote), + true /* show_play_pause_button */, std::move(observer_remote), base::BindLambdaForTesting( [&](mojo::PendingRemote<blink::mojom::PictureInPictureSession> remote, const gfx::Size& b) {
diff --git a/content/browser/picture_in_picture/picture_in_picture_session.cc b/content/browser/picture_in_picture/picture_in_picture_session.cc index 99cba809..0fab46b 100644 --- a/content/browser/picture_in_picture/picture_in_picture_session.cc +++ b/content/browser/picture_in_picture/picture_in_picture_session.cc
@@ -18,7 +18,6 @@ const base::Optional<viz::SurfaceId>& surface_id, const gfx::Size& natural_size, bool show_play_pause_button, - bool show_mute_button, mojo::PendingReceiver<blink::mojom::PictureInPictureSession> receiver, mojo::PendingRemote<blink::mojom::PictureInPictureSessionObserver> observer, gfx::Size* window_size) @@ -32,7 +31,6 @@ GetController().SetActiveSession(this); GetController().EmbedSurface(surface_id.value(), natural_size); GetController().SetAlwaysHidePlayPauseButton(show_play_pause_button); - GetController().SetAlwaysHideMuteButton(show_mute_button); GetController().Show(); *window_size = GetController().GetSize(); @@ -50,13 +48,11 @@ uint32_t player_id, const base::Optional<viz::SurfaceId>& surface_id, const gfx::Size& natural_size, - bool show_play_pause_button, - bool show_mute_button) { + bool show_play_pause_button) { player_id_ = MediaPlayerId(service_->render_frame_host_, player_id); GetController().EmbedSurface(surface_id.value(), natural_size); GetController().SetAlwaysHidePlayPauseButton(show_play_pause_button); - GetController().SetAlwaysHideMuteButton(show_mute_button); GetController().SetActiveSession(this); }
diff --git a/content/browser/picture_in_picture/picture_in_picture_session.h b/content/browser/picture_in_picture/picture_in_picture_session.h index fe080c9..d1030e5 100644 --- a/content/browser/picture_in_picture/picture_in_picture_session.h +++ b/content/browser/picture_in_picture/picture_in_picture_session.h
@@ -33,7 +33,6 @@ const base::Optional<viz::SurfaceId>& surface_id, const gfx::Size& natural_size, bool show_play_pause_button, - bool show_mute_button, mojo::PendingReceiver<blink::mojom::PictureInPictureSession> receiver, mojo::PendingRemote<blink::mojom::PictureInPictureSessionObserver> observer, @@ -45,8 +44,7 @@ void Update(uint32_t player_id, const base::Optional<viz::SurfaceId>& surface_id, const gfx::Size& natural_size, - bool show_play_pause_button, - bool show_mute_button) final; + bool show_play_pause_button) final; void NotifyWindowResized(const gfx::Size& size);
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc index 0b609df..84fc728 100644 --- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc +++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
@@ -201,34 +201,10 @@ return true /* playing */; } -void PictureInPictureWindowControllerImpl::UpdateMutedState() { - if (!window_) - return; - - if (always_hide_mute_button_) { - window_->SetMutedState(OverlayWindow::MutedState::kNoAudio); - return; - } - - window_->SetMutedState(IsPlayerMuted() ? OverlayWindow::MutedState::kMuted - : OverlayWindow::MutedState::kUnmuted); -} - -bool PictureInPictureWindowControllerImpl::ToggleMute() { - DCHECK(window_); - - bool new_muted_status = !IsPlayerMuted(); - media_player_id_->render_frame_host->Send(new MediaPlayerDelegateMsg_Muted( - media_player_id_->render_frame_host->GetRoutingID(), - media_player_id_->delegate_id, new_muted_status)); - return new_muted_status; -} - void PictureInPictureWindowControllerImpl::UpdateMediaPlayerId() { media_player_id_ = active_session_ ? active_session_->player_id() : base::nullopt; UpdatePlaybackState(IsPlayerActive(), !media_player_id_.has_value()); - UpdateMutedState(); } void PictureInPictureWindowControllerImpl::SetActiveSession( @@ -248,12 +224,6 @@ UpdatePlayPauseButtonVisibility(); } -void PictureInPictureWindowControllerImpl::SetAlwaysHideMuteButton( - bool is_visible) { - always_hide_mute_button_ = !is_visible; - UpdateMutedState(); -} - void PictureInPictureWindowControllerImpl::SkipAd() { if (media_session_action_skip_ad_handled_) MediaSession::Get(initiator_)->SkipAd(); @@ -317,7 +287,6 @@ return; UpdatePlaybackState(true /* is_playing */, false /* reached_end_of_stream */); - UpdateMutedState(); } void PictureInPictureWindowControllerImpl::MediaStoppedPlaying( @@ -335,58 +304,6 @@ reason == WebContentsObserver::MediaStoppedReason::kReachedEndOfStream); } -void PictureInPictureWindowControllerImpl::MediaMutedStatusChanged( - const MediaPlayerId& media_player_id, - bool muted) { - if (initiator_->IsBeingDestroyed()) - return; - - if (muted) - AddMutedPlayerEntry(media_player_id); - else - RemoveMutedPlayerEntry(media_player_id); - - if (media_player_id_ == media_player_id) - UpdateMutedState(); -} - -void PictureInPictureWindowControllerImpl::AddMutedPlayerEntry( - const MediaPlayerId& id) { - muted_players_[id.render_frame_host].insert(id.delegate_id); -} - -bool PictureInPictureWindowControllerImpl::RemoveMutedPlayerEntry( - const MediaPlayerId& id) { - auto it = muted_players_.find(id.render_frame_host); - if (it == muted_players_.end()) - return false; - - // Remove the player. - bool did_remove = it->second.erase(id.delegate_id) == 1; - if (!did_remove) - return false; - - // If there are no players left, remove the entry. - if (it->second.empty()) - muted_players_.erase(it); - - return true; -} - -bool PictureInPictureWindowControllerImpl::IsPlayerMuted() { - // At creation time, the player id may not be set. - if (!media_player_id_.has_value()) - return false; - - const auto& players = - muted_players_.find(media_player_id_->render_frame_host); - if (players == muted_players_.end()) - return false; - - return players->second.find(media_player_id_->delegate_id) != - players->second.end(); -} - void PictureInPictureWindowControllerImpl::OnLeavingPictureInPicture( bool should_pause_video) { if (IsPlayerActive() && should_pause_video) {
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h index 4b918964..9e04efb 100644 --- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h +++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
@@ -43,7 +43,6 @@ ~PictureInPictureWindowControllerImpl() override; using PlayerSet = std::set<int>; - using MutedMediaPlayerMap = std::map<RenderFrameHost*, PlayerSet>; // PictureInPictureWindowController: CONTENT_EXPORT void Show() override; @@ -53,15 +52,11 @@ CONTENT_EXPORT OverlayWindow* GetWindowForTesting() override; CONTENT_EXPORT void UpdateLayerBounds() override; CONTENT_EXPORT bool IsPlayerActive() override; - CONTENT_EXPORT bool IsPlayerMuted() override; CONTENT_EXPORT WebContents* GetInitiatorWebContents() override; CONTENT_EXPORT bool TogglePlayPause() override; - CONTENT_EXPORT bool ToggleMute() override; CONTENT_EXPORT void UpdatePlaybackState(bool is_playing, bool reached_end_of_stream) override; - CONTENT_EXPORT void UpdateMutedState() override; CONTENT_EXPORT void SetAlwaysHidePlayPauseButton(bool is_visible) override; - CONTENT_EXPORT void SetAlwaysHideMuteButton(bool is_visible) override; CONTENT_EXPORT void SkipAd() override; CONTENT_EXPORT void NextTrack() override; CONTENT_EXPORT void PreviousTrack() override; @@ -77,7 +72,6 @@ void MediaStoppedPlaying(const MediaPlayerInfo&, const MediaPlayerId&, WebContentsObserver::MediaStoppedReason) override; - void MediaMutedStatusChanged(const MediaPlayerId&, bool muted) override; // TODO(mlamouri): temporary method used because of the media player id is // stored in a different location from the one that is used to update the @@ -118,10 +112,6 @@ // always_hide_play_pause_button_ is false. void UpdatePlayPauseButtonVisibility(); - // Used to add/remove a muted player entry to |muted_players_|. - void AddMutedPlayerEntry(const MediaPlayerId& id); - bool RemoveMutedPlayerEntry(const MediaPlayerId& id); - std::unique_ptr<OverlayWindow> window_; // TODO(929156): remove this as it should be accessible via `web_contents()`. @@ -134,9 +124,6 @@ viz::SurfaceId surface_id_; - // Used to track the muted state of all players. - MutedMediaPlayerMap muted_players_; - // Used to show/hide some actions in Picture-in-Picture window. These are set // to true when website handles some Media Session actions. bool media_session_action_play_handled_ = false; @@ -150,10 +137,6 @@ // Session API in UpdatePlayPauseButtonVisibility(). bool always_hide_play_pause_button_ = false; - // Used to hide mute button if video has no audio track or if MuteButton - // origin trial is disabled. - bool always_hide_mute_button_ = false; - // Session currently associated with the Picture-in-Picture window. The // session object makes the bridge with the renderer process by handling // requests and holding states such as the active player id.
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc index 6074939..f452b49 100644 --- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc +++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -75,12 +75,7 @@ // DefWindowProc so it can generate WM_APPCOMMAND as necessary. bool ShouldGenerateAppCommand(const ui::MouseEvent* event) { #if defined(OS_WIN) - switch (event->native_event().message) { - case WM_XBUTTONUP: - return !base::FeatureList::IsEnabled(features::kExtendedMouseButtons); - case WM_NCXBUTTONUP: - return true; - } + return (event->native_event().message == WM_NCXBUTTONUP); #endif return false; } @@ -628,7 +623,7 @@ case WM_XBUTTONDOWN: case WM_XBUTTONUP: case WM_XBUTTONDBLCLK: - return base::FeatureList::IsEnabled(features::kExtendedMouseButtons); + return true; case WM_NCMOUSELEAVE: case WM_NCMOUSEMOVE: case WM_NCLBUTTONDOWN: @@ -647,22 +642,6 @@ default: break; } -#elif defined(USE_X11) - if (!base::FeatureList::IsEnabled(features::kExtendedMouseButtons)) { - // Renderer only supports standard mouse buttons, so ignore programmable - // buttons. - switch (event->type()) { - case ui::ET_MOUSE_PRESSED: - case ui::ET_MOUSE_RELEASED: { - const int kAllowedButtons = ui::EF_LEFT_MOUSE_BUTTON | - ui::EF_MIDDLE_MOUSE_BUTTON | - ui::EF_RIGHT_MOUSE_BUTTON; - return (event->flags() & kAllowedButtons) != 0; - } - default: - break; - } - } #endif return true; }
diff --git a/content/browser/sms/sms_browsertest.cc b/content/browser/sms/sms_browsertest.cc index f5b1a4d..3a187766 100644 --- a/content/browser/sms/sms_browsertest.cc +++ b/content/browser/sms/sms_browsertest.cc
@@ -95,8 +95,7 @@ } // namespace -// Flaky. crbug.com/997549 -IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_Receive) { +IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Receive) { GURL url = GetTestUrl(nullptr, "simple_page.html"); NavigateToURL(shell(), url); @@ -124,15 +123,21 @@ provider->NotifyReceive(url::Origin::Create(url), "hello"); })); + // Wait for UKM to be recorded to avoid race condition. + base::RunLoop ukm_loop; + ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName, + ukm_loop.QuitClosure()); + EXPECT_EQ("hello", EvalJs(shell(), script)); + ukm_loop.Run(); + ASSERT_FALSE(provider->HasObservers()); ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess); } -// Flaky. crbug.com/997549 -IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_AtMostOnePendingSmsRequest) { +IN_PROC_BROWSER_TEST_F(SmsBrowserTest, AtMostOnePendingSmsRequest) { GURL url = GetTestUrl(nullptr, "simple_page.html"); NavigateToURL(shell(), url); @@ -159,23 +164,35 @@ loop.Quit(); })); + // Wait for UKM to be recorded to avoid race condition. + base::RunLoop ukm_loop1; + ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName, + ukm_loop1.QuitClosure()); + EXPECT_EQ("AbortError", EvalJs(shell(), script)); + loop.Run(); + ukm_loop1.Run(); + ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kCancelled); - loop.Run(); + // Wait for UKM to be recorded to avoid race condition. + base::RunLoop ukm_loop2; + ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName, + ukm_loop2.QuitClosure()); provider->NotifyReceive(url::Origin::Create(url), "hello"); EXPECT_EQ("hello", EvalJs(shell(), "first")); + ukm_loop2.Run(); + ASSERT_FALSE(provider->HasObservers()); ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess); } -// Flaky. crbug.com/997549 -IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_Reload) { +IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Reload) { GURL url = GetTestUrl(nullptr, "simple_page.html"); NavigateToURL(shell(), url); @@ -206,7 +223,6 @@ // Wait for UKM to be recorded to avoid race condition. base::RunLoop ukm_loop; - ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName, ukm_loop.QuitClosure()); @@ -252,8 +268,7 @@ ExpectNoOutcomeUKM(); } -// Flaky. crbug.com/997549 -IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_TwoTabsSameOrigin) { +IN_PROC_BROWSER_TEST_F(SmsBrowserTest, TwoTabsSameOrigin) { auto* provider = new NiceMock<MockSmsProvider>(); BrowserMainLoop::GetInstance()->SetSmsProviderForTesting( base::WrapUnique(provider)); @@ -307,6 +322,7 @@ { base::RunLoop loop; + base::RunLoop ukm_loop; EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _)) .WillOnce( @@ -316,20 +332,27 @@ loop.Quit(); })); + // Wait for UKM to be recorded to avoid race condition. + ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName, + ukm_loop.QuitClosure()); + provider->NotifyReceive(url::Origin::Create(url), "hello1"); loop.Run(); + ukm_loop.Run(); } EXPECT_EQ("hello1", EvalJs(tab1, "sms")); ASSERT_TRUE(provider->HasObservers()); + ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess); + + ukm_recorder()->Purge(); + { base::RunLoop loop; - ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess); - - ukm_recorder()->Purge(); + base::RunLoop ukm_loop; EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _)) .WillOnce( @@ -339,9 +362,14 @@ loop.Quit(); })); + // Wait for UKM to be recorded to avoid race condition. + ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName, + ukm_loop.QuitClosure()); + provider->NotifyReceive(url::Origin::Create(url), "hello2"); loop.Run(); + ukm_loop.Run(); } EXPECT_EQ("hello2", EvalJs(tab2, "sms")); @@ -351,8 +379,7 @@ ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess); } -// Flaky. crbug.com/997549 -IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_TwoTabsDifferentOrigin) { +IN_PROC_BROWSER_TEST_F(SmsBrowserTest, TwoTabsDifferentOrigin) { auto* provider = new NiceMock<MockSmsProvider>(); BrowserMainLoop::GetInstance()->SetSmsProviderForTesting( base::WrapUnique(provider)); @@ -396,6 +423,7 @@ { base::RunLoop loop; + base::RunLoop ukm_loop; EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _)) .WillOnce( Invoke([&loop](RenderFrameHost*, const url::Origin&, @@ -403,8 +431,12 @@ std::move(on_confirm).Run(); loop.Quit(); })); + // Wait for UKM to be recorded to avoid race condition. + ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName, + ukm_loop.QuitClosure()); provider->NotifyReceive(url::Origin::Create(url1), "hello1"); loop.Run(); + ukm_loop.Run(); } EXPECT_EQ("hello1", EvalJs(tab1, "sms")); @@ -413,6 +445,7 @@ { base::RunLoop loop; + base::RunLoop ukm_loop; EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _)) .WillOnce( Invoke([&loop](RenderFrameHost*, const url::Origin&, @@ -420,8 +453,12 @@ std::move(on_confirm).Run(); loop.Quit(); })); + // Wait for UKM to be recorded to avoid race condition. + ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName, + ukm_loop.QuitClosure()); provider->NotifyReceive(url::Origin::Create(url2), "hello2"); loop.Run(); + ukm_loop.Run(); } EXPECT_EQ("hello2", EvalJs(tab2, "sms")); @@ -463,8 +500,7 @@ ExpectNoOutcomeUKM(); } -// Flaky. crbug.com/997549 -IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_Cancels) { +IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Cancels) { GURL url = GetTestUrl(nullptr, "simple_page.html"); NavigateToURL(shell(), url); @@ -475,6 +511,7 @@ shell()->web_contents()->SetDelegate(&delegate_); base::RunLoop loop; + base::RunLoop ukm_loop; EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _)) .WillOnce(Invoke([&loop](RenderFrameHost*, const url::Origin&, @@ -488,6 +525,10 @@ provider->NotifyReceive(url::Origin::Create(url), "hello"); })); + // Wait for UKM to be recorded to avoid race condition. + ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName, + ukm_loop.QuitClosure()); + std::string script = R"( navigator.sms.receive({timeout: 60}).catch(({name}) => { error = name; @@ -498,6 +539,7 @@ EXPECT_EQ(true, EvalJs(shell(), script)); loop.Run(); + ukm_loop.Run(); EXPECT_EQ("AbortError", EvalJs(shell(), "error"));
diff --git a/content/browser/theme_helper_mac.mm b/content/browser/theme_helper_mac.mm index 8bb37de..8ccfbb9 100644 --- a/content/browser/theme_helper_mac.mm +++ b/content/browser/theme_helper_mac.mm
@@ -52,14 +52,27 @@ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; [defaults synchronize]; + // NSScrollerButtonDelay and NSScrollerButtonPeriod are no longer initialized + // in +[NSApplication _initializeRegisteredDefaults] as of 10.15. Their values + // still seem to affect behavior, but their use is logged as an "unusual app + // config", so it's not clear how much longer they'll be implemented. + params->has_initial_button_delay = + [defaults objectForKey:@"NSScrollerButtonDelay"] != nil; params->initial_button_delay = [defaults floatForKey:@"NSScrollerButtonDelay"]; + params->has_autoscroll_button_delay = + [defaults objectForKey:@"NSScrollerButtonPeriod"] != nil; params->autoscroll_button_delay = [defaults floatForKey:@"NSScrollerButtonPeriod"]; params->jump_on_track_click = [defaults boolForKey:@"AppleScrollerPagingBehavior"]; params->preferred_scroller_style = ThemeHelperMac::GetPreferredScrollerStyle(); + + // One one hand, this constant isn't registered anywhere. On the other hand, + // this constant is still (as of 10.15) being used by AppKit to draw controls. + // On the other other hand, this value sent over the wire is actually ignored. + // TODO(https://crbug.com/997934): Figure out why it's being ignored. params->button_placement = GetButtonPlacement(); id rubber_band_value = [defaults objectForKey:@"NSScrollViewRubberbanding"];
diff --git a/content/browser/wake_lock/wake_lock_context_host.cc b/content/browser/wake_lock/wake_lock_context_host.cc index e5088822e..805c006 100644 --- a/content/browser/wake_lock/wake_lock_context_host.cc +++ b/content/browser/wake_lock/wake_lock_context_host.cc
@@ -40,7 +40,7 @@ connector->BindInterface(device::mojom::kServiceName, mojo::MakeRequest(&wake_lock_provider)); wake_lock_provider->GetWakeLockContextForID( - id_, mojo::MakeRequest(&wake_lock_context_)); + id_, wake_lock_context_.BindNewPipeAndPassReceiver()); } }
diff --git a/content/browser/wake_lock/wake_lock_context_host.h b/content/browser/wake_lock/wake_lock_context_host.h index 4100e3c..005d0c5 100644 --- a/content/browser/wake_lock/wake_lock_context_host.h +++ b/content/browser/wake_lock/wake_lock_context_host.h
@@ -6,6 +6,7 @@ #define CONTENT_BROWSER_WAKE_LOCK_WAKE_LOCK_CONTEXT_HOST_H_ #include "content/public/browser/web_contents.h" +#include "mojo/public/cpp/bindings/remote.h" #include "services/device/public/mojom/wake_lock_context.mojom.h" #include "services/device/public/mojom/wake_lock_provider.mojom.h" #include "ui/gfx/native_widget_types.h" @@ -27,7 +28,7 @@ // Returns the WakeLockContext* to which this instance is connected. device::mojom::WakeLockContext* GetWakeLockContext() { - return wake_lock_context_.get(); + return wake_lock_context_ ? wake_lock_context_.get() : nullptr; } private: @@ -38,7 +39,7 @@ WebContents* web_contents_; // The WakeLockContext instance that is connected to this instance. - device::mojom::WakeLockContextPtr wake_lock_context_; + mojo::Remote<device::mojom::WakeLockContext> wake_lock_context_; DISALLOW_COPY_AND_ASSIGN(WakeLockContextHost); };
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom index fb2de84..3750287 100644 --- a/content/common/renderer.mojom +++ b/content/common/renderer.mojom
@@ -148,12 +148,21 @@ }; struct UpdateScrollbarThemeParams { + // TODO(avi): Update these to optional values when optional numeric types are + // allowed. (https://crbug.com/657632) + bool has_initial_button_delay; float initial_button_delay; + bool has_autoscroll_button_delay; float autoscroll_button_delay; + bool jump_on_track_click; ScrollerStyle preferred_scroller_style; bool redraw; + + // TODO(https://crbug.com/997934): This value is ignored on the receiving end. + // Either remove it, or make it not be ignored. ScrollbarButtonsPlacement button_placement; + bool scroll_view_rubber_banding; };
diff --git a/content/public/browser/overlay_window.h b/content/public/browser/overlay_window.h index 8b3248e..26df3fc 100644 --- a/content/public/browser/overlay_window.h +++ b/content/public/browser/overlay_window.h
@@ -37,12 +37,6 @@ kEndOfVideo, }; - enum MutedState { - kMuted = 0, - kUnmuted, - kNoAudio, - }; - OverlayWindow() = default; virtual ~OverlayWindow() = default; @@ -62,7 +56,6 @@ virtual void UpdateVideoSize(const gfx::Size& natural_size) = 0; virtual void SetPlaybackState(PlaybackState playback_state) = 0; virtual void SetAlwaysHidePlayPauseButton(bool is_visible) = 0; - virtual void SetMutedState(MutedState muted_state) = 0; virtual void SetSkipAdButtonVisibility(bool is_visible) = 0; virtual void SetNextTrackButtonVisibility(bool is_visible) = 0; virtual void SetPreviousTrackButtonVisibility(bool is_visible) = 0;
diff --git a/content/public/browser/picture_in_picture_window_controller.h b/content/public/browser/picture_in_picture_window_controller.h index 884eabc..f7c80a3f 100644 --- a/content/public/browser/picture_in_picture_window_controller.h +++ b/content/public/browser/picture_in_picture_window_controller.h
@@ -43,13 +43,10 @@ virtual OverlayWindow* GetWindowForTesting() = 0; virtual void UpdateLayerBounds() = 0; virtual bool IsPlayerActive() = 0; - virtual bool IsPlayerMuted() = 0; virtual WebContents* GetInitiatorWebContents() = 0; virtual void UpdatePlaybackState(bool is_playing, bool reached_end_of_stream) = 0; - virtual void UpdateMutedState() = 0; virtual void SetAlwaysHidePlayPauseButton(bool is_visible) = 0; - virtual void SetAlwaysHideMuteButton(bool is_visible) = 0; // Called when the user interacts with the "Skip Ad" control. virtual void SkipAd() = 0; @@ -65,9 +62,6 @@ // call. virtual bool TogglePlayPause() = 0; - // Returns true if the player is muted after this call. - virtual bool ToggleMute() = 0; - protected: // Use PictureInPictureWindowController::GetOrCreateForWebContents() to // create an instance.
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 4c942a6..d71a8f7 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -136,10 +136,6 @@ const base::Feature kExpensiveBackgroundTimerThrottling{ "ExpensiveBackgroundTimerThrottling", base::FEATURE_ENABLED_BY_DEFAULT}; -// Enables exposing back/forward mouse buttons to the renderer and the web. -const base::Feature kExtendedMouseButtons{"ExtendedMouseButtons", - base::FEATURE_ENABLED_BY_DEFAULT}; - // When enabled Feature Policy propagation is similar to sandbox flags and, // sandbox flags are implemented on top of Feature Policy. const base::Feature kFeaturePolicyForSandbox{"FeaturePolicyForSandbox",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 95331fd7..9fb9214 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -40,7 +40,6 @@ CONTENT_EXPORT extern const base::Feature kExperimentalAccessibilityLabels; CONTENT_EXPORT extern const base::Feature kExperimentalProductivityFeatures; CONTENT_EXPORT extern const base::Feature kExpensiveBackgroundTimerThrottling; -CONTENT_EXPORT extern const base::Feature kExtendedMouseButtons; CONTENT_EXPORT extern const base::Feature kFeaturePolicyForSandbox; CONTENT_EXPORT extern const base::Feature kFontSrcLocalMatching; CONTENT_EXPORT extern const base::Feature kFractionalScrollOffsets;
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index db56b91..5c40e46 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -208,7 +208,6 @@ "media/webrtc/peer_connection_tracker.h", "media/webrtc/rtc_certificate_generator.cc", "media/webrtc/rtc_certificate_generator.h", - "media/webrtc/rtc_event_log_output_sink.h", "media/webrtc/rtc_event_log_output_sink_proxy.cc", "media/webrtc/rtc_event_log_output_sink_proxy.h", "media/webrtc/rtc_peer_connection_handler.cc", @@ -217,8 +216,6 @@ "media/webrtc/rtc_rtp_receiver.h", "media/webrtc/rtc_rtp_sender.cc", "media/webrtc/rtc_rtp_sender.h", - "media/webrtc/rtc_rtp_source.cc", - "media/webrtc/rtc_rtp_source.h", "media/webrtc/rtc_rtp_transceiver.cc", "media/webrtc/rtc_rtp_transceiver.h", "media/webrtc/rtc_stats.cc",
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc index 54392d8..04f26da 100644 --- a/content/renderer/input/render_widget_input_handler.cc +++ b/content/renderer/input/render_widget_input_handler.cc
@@ -227,6 +227,12 @@ viz::FrameSinkId RenderWidgetInputHandler::GetFrameSinkIdAtPoint( const gfx::PointF& point, gfx::PointF* local_point) { + // This method must only be called on a local root, which is guaranteed to + // have a WebWidget. + // TODO(https://crbug.com/995981): Eventually we should be able to remote this + // DCHECK, since RenderWidget's lifetime [and thus this instance's] will be + // synchronized with the WebWidget. + DCHECK(widget_->GetWebWidget()); gfx::PointF point_in_pixel(point); if (widget_->compositor_deps()->IsUseZoomForDSFEnabled()) { point_in_pixel = gfx::ConvertPointToPixel( @@ -264,6 +270,13 @@ WebInputEventResult RenderWidgetInputHandler::HandleTouchEvent( const blink::WebCoalescedInputEvent& coalesced_event) { + // This method must only be called on non-frozen RenderWidget, which is + // guaranteed to have a WebWidget. + // TODO(https://crbug.com/995981): Eventually we should be able to remote this + // DCHECK, since RenderWidget's lifetime [and thus this instance's] will be + // synchronized with the WebWidget. + DCHECK(widget_->GetWebWidget()); + const WebInputEvent& input_event = coalesced_event.Event(); if (input_event.GetType() == WebInputEvent::kTouchScrollStarted) { @@ -296,6 +309,13 @@ const blink::WebCoalescedInputEvent& coalesced_event, const ui::LatencyInfo& latency_info, HandledEventCallback callback) { + // This method must only be called on non-frozen RenderWidget, which is + // guaranteed to have a WebWidget. + // TODO(https://crbug.com/995981): Eventually we should be able to remote this + // DCHECK, since RenderWidget's lifetime [and thus this instance's] will be + // synchronized with the WebWidget. + DCHECK(widget_->GetWebWidget()); + const WebInputEvent& input_event = coalesced_event.Event(); base::AutoReset<bool> handling_input_event_resetter(&handling_input_event_, true); @@ -583,6 +603,13 @@ std::vector<InjectScrollGestureParams> injected_scroll_params, const WebInputEvent& input_event, const ui::LatencyInfo& original_latency_info) { + // This method must only be called on non-frozen RenderWidget, which is + // guaranteed to have a WebWidget. + // TODO(https://crbug.com/995981): Eventually we should be able to remote this + // DCHECK, since RenderWidget's lifetime [and thus this instance's] will be + // synchronized with the WebWidget. + DCHECK(widget_->GetWebWidget()); + DCHECK(injected_scroll_params.size()); base::TimeTicks original_timestamp;
diff --git a/content/renderer/media/webrtc/rtc_event_log_output_sink.h b/content/renderer/media/webrtc/rtc_event_log_output_sink.h deleted file mode 100644 index b902c687..0000000 --- a/content/renderer/media/webrtc/rtc_event_log_output_sink.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_RTC_EVENT_LOG_OUTPUT_SINK_H_ -#define CONTENT_RENDERER_MEDIA_WEBRTC_RTC_EVENT_LOG_OUTPUT_SINK_H_ - -#include <string> - -namespace content { - -class RtcEventLogOutputSink { - public: - virtual ~RtcEventLogOutputSink() = default; - - virtual void OnWebRtcEventLogWrite(const std::string& output) = 0; -}; - -} // namespace content - -#endif // CONTENT_RENDERER_MEDIA_WEBRTC_RTC_EVENT_LOG_OUTPUT_SINK_H_
diff --git a/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.cc b/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.cc index c9fd9e9..f6e9c0fb 100644 --- a/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.cc +++ b/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.cc
@@ -8,7 +8,7 @@ namespace content { RtcEventLogOutputSinkProxy::RtcEventLogOutputSinkProxy( - RtcEventLogOutputSink* sink) + blink::RtcEventLogOutputSink* sink) : sink_(sink) { CHECK(sink_); }
diff --git a/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h b/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h index a3412d60..5ef9754d 100644 --- a/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h +++ b/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h
@@ -5,14 +5,14 @@ #ifndef CONTENT_RENDERER_MEDIA_WEBRTC_RTC_EVENT_LOG_OUTPUT_SINK_PROXY_H_ #define CONTENT_RENDERER_MEDIA_WEBRTC_RTC_EVENT_LOG_OUTPUT_SINK_PROXY_H_ -#include "content/renderer/media/webrtc/rtc_event_log_output_sink.h" +#include "third_party/blink/public/platform/modules/peerconnection/rtc_event_log_output_sink.h" #include "third_party/webrtc/api/rtc_event_log_output.h" namespace content { class RtcEventLogOutputSinkProxy final : public webrtc::RtcEventLogOutput { public: - RtcEventLogOutputSinkProxy(RtcEventLogOutputSink* sink); + RtcEventLogOutputSinkProxy(blink::RtcEventLogOutputSink* sink); ~RtcEventLogOutputSinkProxy() override; bool IsActive() const override; @@ -20,7 +20,7 @@ bool Write(const std::string& output) override; private: - RtcEventLogOutputSink* const sink_; + blink::RtcEventLogOutputSink* const sink_; }; } // namespace content
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc index 6727fab..04239d9 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -31,7 +31,6 @@ #include "content/public/common/content_switches.h" #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" #include "content/renderer/media/webrtc/peer_connection_tracker.h" -#include "content/renderer/media/webrtc/rtc_event_log_output_sink.h" #include "content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h" #include "content/renderer/media/webrtc/rtc_stats.h" #include "content/renderer/media/webrtc/webrtc_set_description_observer.h" @@ -39,6 +38,7 @@ #include "media/base/media_switches.h" #include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_track.h" #include "third_party/blink/public/platform/modules/mediastream/webrtc_uma_histograms.h" +#include "third_party/blink/public/platform/modules/peerconnection/rtc_event_log_output_sink.h" #include "third_party/blink/public/platform/web_media_constraints.h" #include "third_party/blink/public/platform/web_rtc_answer_options.h" #include "third_party/blink/public/platform/web_rtc_data_channel_init.h" @@ -810,7 +810,7 @@ class RTCPeerConnectionHandler::Observer : public base::RefCountedThreadSafe<RTCPeerConnectionHandler::Observer>, public PeerConnectionObserver, - public RtcEventLogOutputSink { + public blink::RtcEventLogOutputSink { public: Observer(const base::WeakPtr<RTCPeerConnectionHandler>& handler, scoped_refptr<base::SingleThreadTaskRunner> task_runner)
diff --git a/content/renderer/media/webrtc/rtc_rtp_receiver.cc b/content/renderer/media/webrtc/rtc_rtp_receiver.cc index 651480e4..2ad7cc7 100644 --- a/content/renderer/media/webrtc/rtc_rtp_receiver.cc +++ b/content/renderer/media/webrtc/rtc_rtp_receiver.cc
@@ -6,9 +6,9 @@ #include "base/bind.h" #include "base/logging.h" -#include "content/renderer/media/webrtc/rtc_rtp_source.h" #include "content/renderer/media/webrtc/rtc_stats.h" #include "content/renderer/media/webrtc/webrtc_util.h" +#include "third_party/blink/public/platform/web_rtc_rtp_source.h" #include "third_party/webrtc/api/scoped_refptr.h" namespace content { @@ -163,7 +163,7 @@ blink::WebVector<std::unique_ptr<blink::WebRTCRtpSource>> sources( webrtc_sources.size()); for (size_t i = 0; i < webrtc_sources.size(); ++i) { - sources[i] = std::make_unique<RTCRtpSource>(webrtc_sources[i]); + sources[i] = blink::CreateRTCRtpSource(webrtc_sources[i]); } return sources; }
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 47689892..fd8be9b 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -2138,7 +2138,12 @@ mojom::UpdateScrollbarThemeParamsPtr params) { #if defined(OS_MACOSX) blink::WebScrollbarTheme::UpdateScrollbarsWithNSDefaults( - params->initial_button_delay, params->autoscroll_button_delay, + params->has_initial_button_delay + ? base::make_optional(params->initial_button_delay) + : base::nullopt, + params->has_autoscroll_button_delay + ? base::make_optional(params->autoscroll_button_delay) + : base::nullopt, params->preferred_scroller_style, params->redraw, params->jump_on_track_click);
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 8db1a1a..e46ef5e 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -722,12 +722,6 @@ void RenderWidget::OnSynchronizeVisualProperties( const VisualProperties& original_params) { - // TODO:(https://crbug.com/995981): If there is no WebWidget, then the - // RenderWidget should also be destroyed, and this conditional should not be - // necessary. - if (!GetWebWidget()) - return; - TRACE_EVENT0("renderer", "RenderWidget::OnSynchronizeVisualProperties"); VisualProperties params = original_params; @@ -1135,6 +1129,11 @@ void RenderWidget::DoRequestNewLayerTreeFrameSink( LayerTreeFrameSinkCallback callback) { + // TODO:(https://crbug.com/995981): If there is no WebWidget, then the + // RenderWidget should also be destroyed, and this DCHECK should not be + // necessary. + DCHECK(GetWebWidget()); + // TODO(jonross): have this generated by the LayerTreeFrameSink itself, which // would then handle binding. mojom::RenderFrameMetadataObserverPtr ptr; @@ -1572,6 +1571,10 @@ browser_controls_shrink_blink_size_); return; } + // TODO:(https://crbug.com/995981): If there is no WebWidget, then the + // RenderWidget should also be destroyed, and this DCHECK should not be + // necessary. + DCHECK(GetWebWidget()); GetWebWidget()->Resize(size); } @@ -2564,6 +2567,15 @@ } void RenderWidget::SetIsFullscreen(bool fullscreen) { + // TODO:(https://crbug.com/995981): If there is no WebWidget, then the + // RenderWidget should also be destroyed, and this conditional should not be + // necessary. + // We intentionally avoid setting internal state so that the next time visual + // properties are synchronized, state will be correctly propagated to the + // WebWidget. + if (!GetWebWidget()) + return; + if (fullscreen == is_fullscreen_granted_) return; is_fullscreen_granted_ = fullscreen;
diff --git a/content/shell/browser/web_test/web_test_content_browser_client.cc b/content/shell/browser/web_test/web_test_content_browser_client.cc index 1a159e8..e0e6f18 100644 --- a/content/shell/browser/web_test/web_test_content_browser_client.cc +++ b/content/shell/browser/web_test/web_test_content_browser_client.cc
@@ -74,7 +74,6 @@ } void SetPlaybackState(PlaybackState playback_state) override {} void SetAlwaysHidePlayPauseButton(bool is_visible) override {} - void SetMutedState(MutedState muted_state) override {} void SetSkipAdButtonVisibility(bool is_visible) override {} void SetNextTrackButtonVisibility(bool is_visible) override {} void SetPreviousTrackButtonVisibility(bool is_visible) override {}
diff --git a/content/shell/test_runner/event_sender.cc b/content/shell/test_runner/event_sender.cc index 6ae9aa6..8f95b775 100644 --- a/content/shell/test_runner/event_sender.cc +++ b/content/shell/test_runner/event_sender.cc
@@ -733,9 +733,6 @@ .SetMethod("setTouchCancelable", &EventSenderBindings::SetTouchCancelable) .SetMethod("dumpFilenameBeingDragged", &EventSenderBindings::DumpFilenameBeingDragged) - .SetMethod("gestureFlingCancel", &EventSenderBindings::GestureFlingCancel) - .SetMethod("gestureFlingStart", &EventSenderBindings::GestureFlingStart) - .SetMethod("isFlinging", &EventSenderBindings::IsFlinging) .SetMethod("gestureScrollFirstPoint", &EventSenderBindings::GestureScrollFirstPoint) .SetMethod("touchStart", &EventSenderBindings::TouchStart) @@ -890,26 +887,6 @@ sender_->DumpFilenameBeingDragged(); } -void EventSenderBindings::GestureFlingCancel() { - if (sender_) - sender_->GestureFlingCancel(); -} - -void EventSenderBindings::GestureFlingStart(float x, - float y, - float velocity_x, - float velocity_y, - gin::Arguments* args) { - if (sender_) - sender_->GestureFlingStart(x, y, velocity_x, velocity_y, args); -} - -bool EventSenderBindings::IsFlinging() { - if (sender_) - return sender_->IsFlinging(); - return false; -} - void EventSenderBindings::GestureScrollFirstPoint(float x, float y) { if (sender_) sender_->GestureScrollFirstPoint(x, y); @@ -1952,65 +1929,6 @@ } } -void EventSender::GestureFlingCancel() { - WebGestureEvent event(WebInputEvent::kGestureFlingCancel, - WebInputEvent::kNoModifiers, GetCurrentEventTime(), - blink::WebGestureDevice::kTouchpad); - // Generally it won't matter what device we use here, and since it might - // be cumbersome to expect all callers to specify a device, we'll just - // choose Touchpad here. - - if (force_layout_on_events_) - UpdateLifecycleToPrePaint(); - - HandleInputEventOnViewOrPopup(event); -} - -void EventSender::GestureFlingStart(float x, - float y, - float velocity_x, - float velocity_y, - gin::Arguments* args) { - WebGestureEvent event(WebInputEvent::kGestureFlingStart, - WebInputEvent::kNoModifiers, GetCurrentEventTime()); - - std::string device_string; - if (!args->PeekNext().IsEmpty() && args->PeekNext()->IsString()) - args->GetNext(&device_string); - - if (device_string == kSourceDeviceStringTouchpad) { - event.SetSourceDevice(blink::WebGestureDevice::kTouchpad); - } else if (device_string == kSourceDeviceStringTouchscreen) { - event.SetSourceDevice(blink::WebGestureDevice::kTouchscreen); - } else { - args->ThrowError(); - return; - } - - float max_start_velocity = std::max(fabs(velocity_x), fabs(velocity_y)); - if (!max_start_velocity) { - v8::Isolate* isolate = blink::MainThreadIsolate(); - isolate->ThrowException(v8::Exception::TypeError( - gin::StringToV8(isolate, "Invalid max start velocity."))); - return; - } - - event.SetPositionInWidget(WebFloatPoint(x, y)); - event.SetPositionInScreen(WebFloatPoint(x, y)); - - event.data.fling_start.velocity_x = velocity_x; - event.data.fling_start.velocity_y = velocity_y; - - if (force_layout_on_events_) - UpdateLifecycleToPrePaint(); - - HandleInputEventOnViewOrPopup(event); -} - -bool EventSender::IsFlinging() { - return mainFrameWidget()->IsFlinging(); -} - void EventSender::GestureScrollFirstPoint(float x, float y) { current_gesture_location_ = WebFloatPoint(x, y); }
diff --git a/content/shell/test_runner/event_sender.h b/content/shell/test_runner/event_sender.h index 8e9d780..4ac763f4 100644 --- a/content/shell/test_runner/event_sender.h +++ b/content/shell/test_runner/event_sender.h
@@ -132,13 +132,6 @@ void DumpFilenameBeingDragged(); - void GestureFlingCancel(); - void GestureFlingStart(float x, - float y, - float velocity_x, - float velocity_y, - gin::Arguments* args); - bool IsFlinging(); void GestureScrollFirstPoint(float x, float y); void TouchStart(gin::Arguments* args);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 45b046c..79bc997a 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -593,6 +593,8 @@ } sources = [ + "../browser/browsing_data/browsing_data_browsertest_utils.cc", + "../browser/browsing_data/browsing_data_browsertest_utils.h", "../public/test/content_browser_test.cc", "../public/test/content_browser_test.h", "../public/test/content_browser_test_utils.cc", @@ -611,6 +613,7 @@ "//base:i18n", "//base/test:test_config", "//base/test:test_support", + "//components/network_session_configurator/common:common", "//components/viz/service", "//content/app:both_for_content_tests", "//content/browser:for_content_tests",
diff --git a/content/test/data/accessibility/html/article-expected-uia-win.txt b/content/test/data/accessibility/html/article-expected-uia-win.txt index efe01316..057c893 100644 --- a/content/test/data/accessibility/html/article-expected-uia-win.txt +++ b/content/test/data/accessibility/html/article-expected-uia-win.txt
@@ -1,3 +1,3 @@ document -++article +++article ControlType='UIA_GroupControlTypeId' LocalizedControlType='article' ++++description Name='This is an article element.'
diff --git a/content/test/data/accessibility/html/article.html b/content/test/data/accessibility/html/article.html index 10af48b..bf9ff949 100644 --- a/content/test/data/accessibility/html/article.html +++ b/content/test/data/accessibility/html/article.html
@@ -2,6 +2,8 @@ @MAC-ALLOW:AXRole* @MAC-ALLOW:AXSubrole=AXDocumentArticle @MAC-DENY:AXTitle* +@UIA-WIN-ALLOW:ControlType='UIA_GroupControlTypeId' +@UIA-WIN-ALLOW:LocalizedControlType='article' @WIN-ALLOW:xml-roles:article @AURALINUX-ALLOW:xml-roles:article -->
diff --git a/content/test/data/accessibility/html/figure-expected-uia-win.txt b/content/test/data/accessibility/html/figure-expected-uia-win.txt index 0c4353e3..1eb4524 100644 --- a/content/test/data/accessibility/html/figure-expected-uia-win.txt +++ b/content/test/data/accessibility/html/figure-expected-uia-win.txt
@@ -1,3 +1,3 @@ document -++group +++group LocalizedControlType='figure' ++++img Name='Sunspots'
diff --git a/content/test/data/accessibility/html/figure-expected-win.txt b/content/test/data/accessibility/html/figure-expected-win.txt index 9359a64..325d0f9273 100644 --- a/content/test/data/accessibility/html/figure-expected-win.txt +++ b/content/test/data/accessibility/html/figure-expected-win.txt
@@ -1,3 +1,3 @@ ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE -++ROLE_SYSTEM_GROUPING xml-roles:figure +++ROLE_SYSTEM_GROUPING xml-roles:figure localized_extended_role='figure' ++++ROLE_SYSTEM_GRAPHIC name='Sunspots' READONLY xml-roles:img
diff --git a/content/test/data/accessibility/html/figure.html b/content/test/data/accessibility/html/figure.html index 49dfa3550..12f6f72 100644 --- a/content/test/data/accessibility/html/figure.html +++ b/content/test/data/accessibility/html/figure.html
@@ -1,5 +1,7 @@ <!-- @MAC-ALLOW:AXRole* +@UIA-WIN-ALLOW:LocalizedControlType='figure' +@WIN-ALLOW:localized_extended_role='figure' @WIN-ALLOW:xml-roles* @AURALINUX-ALLOW:xml-roles* -->
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index 8a964a7..aab4e3a7 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -187,6 +187,7 @@ crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_CanvasDisplaySRGBUnaccelerated2D [ Skip ] crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_CanvasDisplaySRGBUnaccelerated2DGPUCompositing [ Skip ] crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_CanvasUnacceleratedLowLatency2D [ Skip ] +crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_Canvas2DTabSwitch_SoftwareCompositing [ Skip ] crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_OffscreenCanvasUnaccelerated2D [ Skip ] crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_OffscreenCanvasUnaccelerated2DWorker [ Skip ] crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_OffscreenCanvasWebGLSoftwareCompositing [ Skip ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index 61f4399..fa168f73 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -624,6 +624,7 @@ crbug.com/483282 [ linux amd ] deqp/functional/gles3/texturespecification/teximage2d_depth_pbo.html [ Failure ] crbug.com/483282 [ linux amd ] deqp/functional/gles3/draw/random.html [ Failure ] crbug.com/483282 [ linux amd ] deqp/functional/gles3/fbomultisample* [ Failure ] +crbug.com/483282 [ linux amd ] deqp/functional/gles3/framebufferblit/conversion_07.html [ Failure ] crbug.com/658832 [ linux amd ] deqp/functional/gles3/framebufferblit/default_framebuffer_00.html [ Failure ] crbug.com/483282 [ linux amd ] conformance2/glsl3/vector-dynamic-indexing.html [ Failure ] crbug.com/483282 [ no-angle linux amd ] conformance2/reading/read-pixels-pack-parameters.html [ Failure ]
diff --git a/docs/flag_expiry.md b/docs/flag_expiry.md index 889eefb..addc261 100644 --- a/docs/flag_expiry.md +++ b/docs/flag_expiry.md
@@ -56,4 +56,10 @@ TODO(https://crbug.com/953690): Fill in this list :) +## See Also + +* [//chrome/browser/flag-metadata.json](../chrome/browser/flag-metadata.json) +* [//chrome/browser/expired_flags_list.h](../chrome/browser/expired_flags_list.h) +* [//tools/flags/generate_expired_list.py](../tools/flags/generate_expired_list.py) + [file a bug]: https://new.crbug.com
diff --git a/fuchsia/engine/context_provider_impl.cc b/fuchsia/engine/context_provider_impl.cc index d5f4ed1..bf215b6 100644 --- a/fuchsia/engine/context_provider_impl.cc +++ b/fuchsia/engine/context_provider_impl.cc
@@ -84,6 +84,8 @@ } base::LaunchOptions launch_options; + launch_options.process_name_suffix = ":context"; + service_manager::SandboxPolicyFuchsia sandbox_policy; sandbox_policy.Initialize(service_manager::SANDBOX_TYPE_WEB_CONTEXT); sandbox_policy.SetServiceDirectory(std::move(service_directory));
diff --git a/gpu/command_buffer/service/external_vk_image_dawn_representation.cc b/gpu/command_buffer/service/external_vk_image_dawn_representation.cc index 9475f8c..9e08c403 100644 --- a/gpu/command_buffer/service/external_vk_image_dawn_representation.cc +++ b/gpu/command_buffer/service/external_vk_image_dawn_representation.cc
@@ -48,7 +48,7 @@ } DawnTexture ExternalVkImageDawnRepresentation::BeginAccess( - DawnTextureUsageBit usage) { + DawnTextureUsage usage) { std::vector<SemaphoreHandle> handles; if (!backing_impl()->BeginAccess(false, &handles, false /* is_gl */)) {
diff --git a/gpu/command_buffer/service/external_vk_image_dawn_representation.h b/gpu/command_buffer/service/external_vk_image_dawn_representation.h index c040553..e605db8 100644 --- a/gpu/command_buffer/service/external_vk_image_dawn_representation.h +++ b/gpu/command_buffer/service/external_vk_image_dawn_representation.h
@@ -22,7 +22,7 @@ uint32_t memory_type_index); ~ExternalVkImageDawnRepresentation() override; - DawnTexture BeginAccess(DawnTextureUsageBit usage) override; + DawnTexture BeginAccess(DawnTextureUsage usage) override; void EndAccess() override; private:
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm index 5f99d5e4..83dbdec 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm +++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm
@@ -296,7 +296,7 @@ dawn_procs_.deviceRelease(device_); } - DawnTexture BeginAccess(DawnTextureUsageBit usage) final { + DawnTexture BeginAccess(DawnTextureUsage usage) final { DawnTextureDescriptor desc; desc.nextInChain = nullptr; desc.format = dawn_format_;
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc index 3029d83..8438373c 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
@@ -290,9 +290,8 @@ // Clear the shared image to green using Dawn. { - dawn::Texture texture = - dawn::Texture::Acquire(dawn_representation->BeginAccess( - DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT)); + dawn::Texture texture = dawn::Texture::Acquire( + dawn_representation->BeginAccess(DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT)); dawn::RenderPassColorAttachmentDescriptor color_desc; color_desc.attachment = texture.CreateDefaultView();
diff --git a/gpu/command_buffer/service/shared_image_representation.h b/gpu/command_buffer/service/shared_image_representation.h index 6a576d3..30d643c 100644 --- a/gpu/command_buffer/service/shared_image_representation.h +++ b/gpu/command_buffer/service/shared_image_representation.h
@@ -303,7 +303,7 @@ // TODO(penghuang): Add ScopedAccess helper class. // This can return null in case of a Dawn validation error, for example if // usage is invalid. - virtual DawnTexture BeginAccess(DawnTextureUsageBit usage) = 0; + virtual DawnTexture BeginAccess(DawnTextureUsage usage) = 0; virtual void EndAccess() = 0; };
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc index 5d417d2..9aefcad2d 100644 --- a/gpu/command_buffer/service/webgpu_decoder_impl.cc +++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -574,7 +574,7 @@ uint32_t device_generation = static_cast<uint32_t>(c.device_generation); uint32_t id = static_cast<uint32_t>(c.id); uint32_t generation = static_cast<uint32_t>(c.generation); - uint32_t usage = static_cast<DawnTextureUsageBit>(c.usage); + uint32_t usage = static_cast<DawnTextureUsage>(c.usage); // Unpack the mailbox if (sizeof(Mailbox) > immediate_data_size) { @@ -599,14 +599,13 @@ } static constexpr uint32_t kAllowedTextureUsages = static_cast<uint32_t>( - DAWN_TEXTURE_USAGE_BIT_COPY_SRC | DAWN_TEXTURE_USAGE_BIT_COPY_DST | - DAWN_TEXTURE_USAGE_BIT_SAMPLED | - DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT); + DAWN_TEXTURE_USAGE_COPY_SRC | DAWN_TEXTURE_USAGE_COPY_DST | + DAWN_TEXTURE_USAGE_SAMPLED | DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT); if (usage & ~kAllowedTextureUsages) { DLOG(ERROR) << "AssociateMailbox: Invalid usage"; return error::kInvalidArguments; } - DawnTextureUsageBit dawn_usage = static_cast<DawnTextureUsageBit>(usage); + DawnTextureUsage dawn_usage = static_cast<DawnTextureUsage>(usage); // Create a DawnTexture from the mailbox. std::unique_ptr<SharedImageRepresentationDawn> shared_image =
diff --git a/gpu/command_buffer/service/webgpu_decoder_unittest.cc b/gpu/command_buffer/service/webgpu_decoder_unittest.cc index f71be008..7eceeaf 100644 --- a/gpu/command_buffer/service/webgpu_decoder_unittest.cc +++ b/gpu/command_buffer/service/webgpu_decoder_unittest.cc
@@ -109,7 +109,7 @@ { gpu::Mailbox bad_mailbox; AssociateMailboxCmdStorage cmd; - cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_BIT_SAMPLED, bad_mailbox.name); + cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_SAMPLED, bad_mailbox.name); EXPECT_EQ(error::kInvalidArguments, ExecuteImmediateCmd(cmd.cmd, sizeof(bad_mailbox.name))); } @@ -117,7 +117,7 @@ // Error case: device doesn't exist. { AssociateMailboxCmdStorage cmd; - cmd.cmd.Init(42, 42, 1, 0, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name); + cmd.cmd.Init(42, 42, 1, 0, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name); EXPECT_EQ(error::kInvalidArguments, ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name))); } @@ -125,7 +125,7 @@ // Error case: texture ID invalid for the wire server. { AssociateMailboxCmdStorage cmd; - cmd.cmd.Init(0, 0, 42, 42, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name); + cmd.cmd.Init(0, 0, 42, 42, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name); EXPECT_EQ(error::kInvalidArguments, ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name))); } @@ -133,7 +133,7 @@ // Error case: invalid usage. { AssociateMailboxCmdStorage cmd; - cmd.cmd.Init(0, 0, 42, 42, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name); + cmd.cmd.Init(0, 0, 42, 42, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name); EXPECT_EQ(error::kInvalidArguments, ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name))); } @@ -141,7 +141,7 @@ // Error case: invalid texture usage. { AssociateMailboxCmdStorage cmd; - cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_BIT_FORCE32, mailbox.name); + cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_FORCE32, mailbox.name); EXPECT_EQ(error::kInvalidArguments, ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name))); } @@ -153,7 +153,7 @@ // and generation invalid. { AssociateMailboxCmdStorage cmd; - cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name); + cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name); EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name))); } @@ -161,7 +161,7 @@ // Error case: associated to an already associated texture. { AssociateMailboxCmdStorage cmd; - cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name); + cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name); EXPECT_EQ(error::kInvalidArguments, ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name))); } @@ -188,7 +188,7 @@ // Associate a mailbox so we can later dissociate it. { AssociateMailboxCmdStorage cmd; - cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name); + cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name); EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name))); }
diff --git a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc index de124e6..bfc1c4c 100644 --- a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc +++ b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
@@ -97,7 +97,7 @@ webgpu()->ReserveTexture(device.Get()); webgpu()->AssociateMailbox(0, 0, reservation.id, reservation.generation, - DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT, + DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT, reinterpret_cast<GLbyte*>(&mailbox)); dawn::Texture texture = dawn::Texture::Acquire(reservation.texture); @@ -141,15 +141,14 @@ webgpu()->FlushCommands(); webgpu()->AssociateMailbox(0, 0, reservation.id, reservation.generation, - DAWN_TEXTURE_USAGE_BIT_COPY_SRC, + DAWN_TEXTURE_USAGE_COPY_SRC, reinterpret_cast<GLbyte*>(&mailbox)); dawn::Texture texture = dawn::Texture::Acquire(reservation.texture); // Copy the texture in a mappable buffer. dawn::BufferDescriptor buffer_desc; buffer_desc.size = 4; - buffer_desc.usage = - dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::CopyDst; + buffer_desc.usage = dawn::BufferUsage::MapRead | dawn::BufferUsage::CopyDst; dawn::Buffer readback_buffer = device.CreateBuffer(&buffer_desc); dawn::TextureCopyView copy_src; @@ -218,7 +217,7 @@ dawn::Texture texture = dawn::Texture::Acquire(reservation.texture); webgpu()->AssociateMailbox(0, 0, reservation.id, reservation.generation, - DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT, + DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT, reinterpret_cast<GLbyte*>(&mailbox)); webgpu()->DissociateMailbox(reservation.id, reservation.generation);
diff --git a/ios/chrome/app/resources/LaunchScreen.xib b/ios/chrome/app/resources/LaunchScreen.xib index 3008ab66..1bfa3950 100644 --- a/ios/chrome/app/resources/LaunchScreen.xib +++ b/ios/chrome/app/resources/LaunchScreen.xib
@@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14845" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14854.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES"> <device id="retina6_1" orientation="portrait" appearance="light"/> <dependencies> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14799.2"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14806.4"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <objects> @@ -33,7 +33,7 @@ </constraints> </imageView> </subviews> - <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> <constraints> <constraint firstItem="K7H-Iv-QNk" firstAttribute="width" secondItem="tRS-Cx-RH3" secondAttribute="width" multiplier="0.381966" id="3hJ-Yo-1Tg"/> <constraint firstItem="K7H-Iv-QNk" firstAttribute="height" secondItem="tRS-Cx-RH3" secondAttribute="height" multiplier="0.381966" id="962-tL-cOd"/>
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm index 202024a..19c7410 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -15,7 +15,6 @@ #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h" -#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h" #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_features.h" @@ -212,13 +211,6 @@ return browser_state_->GetSyncablePrefs() ->GetSyncableService(syncer::PRIORITY_PREFERENCES) ->AsWeakPtr(); - case syncer::AUTOFILL_WALLET_METADATA: { - if (!profile_web_data_service_) - return base::WeakPtr<syncer::SyncableService>(); - return autofill::AutofillWalletMetadataSyncableService:: - FromWebDataService(profile_web_data_service_.get()) - ->AsWeakPtr(); - } case syncer::HISTORY_DELETE_DIRECTIVES: { history::HistoryService* history = ios::HistoryServiceFactory::GetForBrowserState(
diff --git a/ios/chrome/browser/ui/alert_view_controller/alert_view_controller.mm b/ios/chrome/browser/ui/alert_view_controller/alert_view_controller.mm index 86ea9e4..fd18497b 100644 --- a/ios/chrome/browser/ui/alert_view_controller/alert_view_controller.mm +++ b/ios/chrome/browser/ui/alert_view_controller/alert_view_controller.mm
@@ -118,10 +118,8 @@ if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection: previousTraitCollection]) { - [self.traitCollection performAsCurrentTraitCollection:^{ - self.textFieldStackHolder.layer.borderColor = - UIColor.cr_separatorColor.CGColor; - }]; + self.textFieldStackHolder.layer.borderColor = + UIColor.cr_separatorColor.CGColor; } } }
diff --git a/ios/chrome/browser/ui/bubble/bubble_view.mm b/ios/chrome/browser/ui/bubble/bubble_view.mm index 59b1df1..70e40294 100644 --- a/ios/chrome/browser/ui/bubble/bubble_view.mm +++ b/ios/chrome/browser/ui/bubble/bubble_view.mm
@@ -356,9 +356,7 @@ if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection: previousTraitCollection]) { - UIColor* resolvedColor = - [BubbleColor() resolvedColorWithTraitCollection:self.traitCollection]; - self.arrowLayer.fillColor = resolvedColor.CGColor; + self.arrowLayer.fillColor = BubbleColor().CGColor; } } }
diff --git a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm index 669967ee..e361a59a 100644 --- a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm +++ b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
@@ -275,10 +275,8 @@ if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection: previousTraitCollection]) { - [self.traitCollection performAsCurrentTraitCollection:^{ - [self.view.layer - setShadowColor:[UIColor colorNamed:kToolbarShadowColor].CGColor]; - }]; + [self.view.layer + setShadowColor:[UIColor colorNamed:kToolbarShadowColor].CGColor]; } } }
diff --git a/ios/chrome/browser/ui/open_in/BUILD.gn b/ios/chrome/browser/ui/open_in/BUILD.gn index 4118e0d..3345c393 100644 --- a/ios/chrome/browser/ui/open_in/BUILD.gn +++ b/ios/chrome/browser/ui/open_in/BUILD.gn
@@ -23,7 +23,7 @@ "//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/util", "//ios/chrome/browser/web_state_list", - "//ios/chrome/common/ui_util", + "//ios/chrome/common/colors", "//ios/chrome/common/ui_util", "//ios/third_party/material_components_ios", "//ios/web/public",
diff --git a/ios/chrome/browser/ui/open_in/open_in_toolbar.mm b/ios/chrome/browser/ui/open_in/open_in_toolbar.mm index e16e9a23..6d799e3 100644 --- a/ios/chrome/browser/ui/open_in/open_in_toolbar.mm +++ b/ios/chrome/browser/ui/open_in/open_in_toolbar.mm
@@ -7,10 +7,10 @@ #include <cmath> #include "base/logging.h" -#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" #import "ios/chrome/browser/ui/util/named_guide.h" #include "ios/chrome/browser/ui/util/rtl_geometry.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #import "ios/chrome/common/ui_util/constraints_ui_util.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h" @@ -28,28 +28,17 @@ // The toolbar's border related constants. const CGFloat kTopBorderHeight = 0.5f; -const CGFloat kTopBorderTransparency = 0.13f; -const int kTopBorderColor = 0x000000; - -// The toolbar's background related constants. -const int kToolbarBackgroundColor = 0xFFFFFF; -const CGFloat kToolbarBackgroundTransparency = 0.97f; } // anonymous namespace -@interface OpenInToolbar () { - // Backing object for |self.openButton|. - MDCButton* _openButton; - // Backing object for |self.topBorder|. - UIView* _topBorder; -} +@interface OpenInToolbar () // The "Open in..." button that's hooked up with the target and action passed // on initialization. -@property(nonatomic, retain, readonly) MDCButton* openButton; +@property(nonatomic, strong, readonly) MDCButton* openButton; // The line used as the border at the top of the toolbar. -@property(nonatomic, retain, readonly) UIView* topBorder; +@property(nonatomic, strong, readonly) UIView* topBorder; // View used to have a bottom margin to prevent overlapping with the bottom // toolbar. This view is used because the the CRWWebControllerContainerView is @@ -95,6 +84,8 @@ @synthesize bottomMargin = _bottomMargin; @synthesize bottomMarginConstraint = _bottomMarginConstraint; +@synthesize openButton = _openButton; +@synthesize topBorder = _topBorder; - (instancetype)initWithFrame:(CGRect)aRect { NOTREACHED(); @@ -105,8 +96,7 @@ self = [super initWithFrame:CGRectZero]; if (self) { DCHECK([target respondsToSelector:action]); - [self setBackgroundColor:UIColorFromRGB(kToolbarBackgroundColor, - kToolbarBackgroundTransparency)]; + self.backgroundColor = [UIColor colorNamed:kBackgroundColor]; [self addSubview:self.openButton]; [self.openButton addTarget:target action:action @@ -147,7 +137,7 @@ - (MDCButton*)openButton { if (!_openButton) { _openButton = [[MDCFlatButton alloc] init]; - [_openButton setTitleColor:[[MDCPalette cr_bluePalette] tint500] + [_openButton setTitleColor:[UIColor colorNamed:kBlueColor] forState:UIControlStateNormal]; [_openButton setTitle:l10n_util::GetNSStringWithFixup(IDS_IOS_OPEN_IN) forState:UIControlStateNormal]; @@ -159,8 +149,7 @@ - (UIView*)topBorder { if (!_topBorder) { _topBorder = [[UIView alloc] initWithFrame:CGRectZero]; - [_topBorder setBackgroundColor:UIColorFromRGB(kTopBorderColor, - kTopBorderTransparency)]; + _topBorder.backgroundColor = [UIColor colorNamed:kToolbarShadowColor]; } return _topBorder; }
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm index 1336ae9f..d3ccec9 100644 --- a/ios/web_view/internal/sync/web_view_sync_client.mm +++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -11,7 +11,6 @@ #include "base/logging.h" #include "base/task/post_task.h" #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h" -#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_features.h" #include "components/browser_sync/profile_sync_components_factory_impl.h" @@ -173,16 +172,7 @@ base::WeakPtr<syncer::SyncableService> WebViewSyncClient::GetSyncableServiceForType(syncer::ModelType type) { - auto service = account_web_data_service_ ?: profile_web_data_service_; - if (!service) { - NOTREACHED(); - return base::WeakPtr<syncer::SyncableService>(); - } switch (type) { - case syncer::AUTOFILL_WALLET_METADATA: - return autofill::AutofillWalletMetadataSyncableService:: - FromWebDataService(service.get()) - ->AsWeakPtr(); case syncer::PASSWORDS: return password_store_ ? password_store_->GetPasswordSyncableService() : base::WeakPtr<syncer::SyncableService>();
diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc index bd13c9ac..ade6fbc 100644 --- a/media/cast/test/end2end_unittest.cc +++ b/media/cast/test/end2end_unittest.cc
@@ -28,6 +28,7 @@ #include "base/test/simple_test_tick_clock.h" #include "base/test/task_environment.h" #include "base/time/tick_clock.h" +#include "build/build_config.h" #include "media/base/audio_bus.h" #include "media/base/fake_single_thread_task_runner.h" #include "media/base/video_frame.h" @@ -1218,7 +1219,9 @@ // Tests that a system configured for 30 FPS drops frames when input is provided // at a much higher frame rate. // Fails consistently on official builds: crbug.com/612496 -#ifdef OFFICIAL_BUILD +// crbug.com/997944. Flaky on multiple platforms. +#if defined(OFFICIAL_BUILD) || defined(OS_LINUX) || defined(OS_MACOSX) || \ + defined(OS_WIN) #define MAYBE_ShoveHighFrameRateDownYerThroat \ DISABLED_ShoveHighFrameRateDownYerThroat #else
diff --git a/media/filters/vp9_parser.cc b/media/filters/vp9_parser.cc index f975e7e..2a904b6 100644 --- a/media/filters/vp9_parser.cc +++ b/media/filters/vp9_parser.cc
@@ -531,6 +531,12 @@ stream_decrypt_config_ = std::move(stream_config); } +void Vp9Parser::SetStream(const uint8_t* stream, + off_t stream_size, + std::unique_ptr<DecryptConfig> stream_config) { + SetStream(stream, stream_size, {}, std::move(stream_config)); +} + void Vp9Parser::Reset() { stream_ = nullptr; bytes_left_ = 0;
diff --git a/media/filters/vp9_parser.h b/media/filters/vp9_parser.h index 0aa1bb8..359bafd8 100644 --- a/media/filters/vp9_parser.h +++ b/media/filters/vp9_parser.h
@@ -382,6 +382,10 @@ const std::vector<uint32_t>& spatial_layer_frame_size, std::unique_ptr<DecryptConfig> stream_config); + void SetStream(const uint8_t* stream, + off_t stream_size, + std::unique_ptr<DecryptConfig> stream_config); + // Parse the next frame in the current stream buffer, filling |fhdr| with // the parsed frame header and updating current segmentation and loop filter // state. The necessary frame size to decode |fhdr| fills in |allocate_size|.
diff --git a/media/filters/vp9_parser_encrypted_fuzzertest.cc b/media/filters/vp9_parser_encrypted_fuzzertest.cc index 69e3820b..8b2b4ae 100644 --- a/media/filters/vp9_parser_encrypted_fuzzertest.cc +++ b/media/filters/vp9_parser_encrypted_fuzzertest.cc
@@ -57,7 +57,7 @@ while (ivf_parser.ParseNextFrame(&ivf_frame_header, &ivf_payload)) { media::Vp9FrameHeader vp9_frame_header; vp9_parser.SetStream( - ivf_payload, ivf_frame_header.frame_size, {}, + ivf_payload, ivf_frame_header.frame_size, media::DecryptConfig::CreateCencConfig(key_id, iv, subsamples)); // TODO(kcwu): further fuzzing the case of Vp9Parser::kAwaitingRefresh. std::unique_ptr<media::DecryptConfig> null_config;
diff --git a/media/filters/vp9_parser_fuzzertest.cc b/media/filters/vp9_parser_fuzzertest.cc index 9da885b..a4343d5 100644 --- a/media/filters/vp9_parser_fuzzertest.cc +++ b/media/filters/vp9_parser_fuzzertest.cc
@@ -36,7 +36,7 @@ // Parse until the end of stream/unsupported stream/error in stream is found. while (ivf_parser.ParseNextFrame(&ivf_frame_header, &ivf_payload)) { media::Vp9FrameHeader vp9_frame_header; - vp9_parser.SetStream(ivf_payload, ivf_frame_header.frame_size, {}, nullptr); + vp9_parser.SetStream(ivf_payload, ivf_frame_header.frame_size, nullptr); // TODO(kcwu): further fuzzing the case of Vp9Parser::kAwaitingRefresh. std::unique_ptr<media::DecryptConfig> null_config; gfx::Size allocate_size;
diff --git a/media/filters/vp9_parser_unittest.cc b/media/filters/vp9_parser_unittest.cc index b435229..23816767 100644 --- a/media/filters/vp9_parser_unittest.cc +++ b/media/filters/vp9_parser_unittest.cc
@@ -144,7 +144,7 @@ if (!ivf_parser_.ParseNextFrame(&ivf_frame_header, &ivf_payload)) return Vp9Parser::kEOStream; - vp9_parser_->SetStream(ivf_payload, ivf_frame_header.frame_size, {}, + vp9_parser_->SetStream(ivf_payload, ivf_frame_header.frame_size, nullptr); continue; } @@ -158,7 +158,7 @@ size_t framesize, std::unique_ptr<DecryptConfig> config, std::vector<std::unique_ptr<DecryptConfig>>& expected_split) { - vp9_parser_->SetStream(superframe, framesize, {}, std::move(config)); + vp9_parser_->SetStream(superframe, framesize, std::move(config)); for (auto& expected : expected_split) { std::unique_ptr<DecryptConfig> actual = vp9_parser_->NextFrameDecryptContextForTesting(); @@ -428,7 +428,7 @@ // marker again. superframe_marker_byte}; - vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe), {}, + vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe), DecryptConfig::CreateCencConfig( kKeyID, kInitialIV, {SubsampleEntry(16, 32)})); @@ -459,7 +459,7 @@ // marker again. superframe_marker_byte}; - vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe), {}, + vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe), DecryptConfig::CreateCencConfig( kKeyID, kInitialIV, {SubsampleEntry(0, 48)})); @@ -494,7 +494,7 @@ // marker again. superframe_marker_byte}; - vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe), {}, + vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe), DecryptConfig::CreateCencConfig( kKeyID, kInitialIV, {SubsampleEntry(48, 0)})); @@ -530,7 +530,7 @@ superframe_marker_byte}; vp9_parser_->SetStream( - kSuperframe, sizeof(kSuperframe), {}, + kSuperframe, sizeof(kSuperframe), DecryptConfig::CreateCencConfig(kKeyID, kInitialIV, { SubsampleEntry(16, 16),
diff --git a/media/gpu/test/video_player/test_vda_video_decoder.cc b/media/gpu/test/video_player/test_vda_video_decoder.cc index abc8e9d..cc14231e 100644 --- a/media/gpu/test/video_player/test_vda_video_decoder.cc +++ b/media/gpu/test/video_player/test_vda_video_decoder.cc
@@ -362,19 +362,19 @@ switch (error) { case VideoDecodeAccelerator::ILLEGAL_STATE: - LOG(FATAL) << "ILLEGAL_STATE"; + LOG(ERROR) << "ILLEGAL_STATE"; break; case VideoDecodeAccelerator::INVALID_ARGUMENT: - LOG(FATAL) << "INVALID_ARGUMENT"; + LOG(ERROR) << "INVALID_ARGUMENT"; break; case VideoDecodeAccelerator::UNREADABLE_INPUT: - LOG(FATAL) << "UNREADABLE_INPUT"; + LOG(ERROR) << "UNREADABLE_INPUT"; break; case VideoDecodeAccelerator::PLATFORM_FAILURE: - LOG(FATAL) << "PLATFORM_FAILURE"; + LOG(ERROR) << "PLATFORM_FAILURE"; break; default: - LOG(FATAL) << "Unknown error " << error; + LOG(ERROR) << "Unknown error " << error; break; } }
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc index 2aede768..c4dada1 100644 --- a/media/gpu/video_encode_accelerator_unittest.cc +++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -1057,7 +1057,7 @@ // partition numbers/sizes. For now assume one frame per buffer. Vp9FrameHeader header; gfx::Size allocate_size; - parser_.SetStream(stream, size, {}, nullptr); + parser_.SetStream(stream, size, nullptr); EXPECT_TRUE(Vp9Parser::kInvalidStream != parser_.ParseNextFrame(&header, &allocate_size, nullptr)); if (header.IsKeyframe()) {
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc index fef3a79c..365b1d52 100644 --- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc +++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -412,7 +412,7 @@ // Detects stream configuration changes. // Returns false on failure. bool DetectConfig(const uint8_t* stream, unsigned int size) override { - parser_.SetStream(stream, size, {} /* spatial_layer_frame_size */, nullptr); + parser_.SetStream(stream, size, nullptr); Vp9FrameHeader fhdr; gfx::Size allocate_size; std::unique_ptr<DecryptConfig> null_config;
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc index 079a4df6..de1357af5 100644 --- a/media/renderers/video_resource_updater.cc +++ b/media/renderers/video_resource_updater.cc
@@ -70,7 +70,13 @@ case PIXEL_FORMAT_UYVY: case PIXEL_FORMAT_ABGR: DCHECK_EQ(num_textures, 1); - buffer_formats[0] = gfx::BufferFormat::RGBA_8888; + // This maps VideoPixelFormat back to GMB BufferFormat + // NOTE: ABGR == RGBA and ARGB == BGRA, they differ only byte order + // See: VideoFormat function in gpu_memory_buffer_video_frame_pool + // https://cs.chromium.org/chromium/src/media/video/gpu_memory_buffer_video_frame_pool.cc?type=cs&g=0&l=281 + buffer_formats[0] = (format == PIXEL_FORMAT_ABGR) + ? gfx::BufferFormat::RGBA_8888 + : gfx::BufferFormat::BGRA_8888; switch (target) { case GL_TEXTURE_EXTERNAL_OES: if (use_stream_video_draw_quad)
diff --git a/net/extras/sqlite/sqlite_persistent_store_backend_base.cc b/net/extras/sqlite/sqlite_persistent_store_backend_base.cc index 805d5ee9..82d8c6e 100644 --- a/net/extras/sqlite/sqlite_persistent_store_backend_base.cc +++ b/net/extras/sqlite/sqlite_persistent_store_backend_base.cc
@@ -102,6 +102,7 @@ Reset(); return false; } + db_->Preload(); if (!MigrateDatabaseSchema() || !CreateDatabaseSchema()) { DLOG(ERROR) << "Unable to update or initialize " << histogram_tag_
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index 11a0cc4..cccfe47 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc
@@ -1427,7 +1427,7 @@ // created a new ActiveEntry (new_entry_) to write to (and doomed the old // one). Now that the new entry has been created, start writing the response. - DCHECK_EQ(result, OK); + CHECK_EQ(result, OK); DCHECK_EQ(mode_, WRITE); DCHECK(new_entry_); DCHECK(response_.headers);
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index d72f011d..6228b488 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc
@@ -44,13 +44,6 @@ using protocol::ActionRequest; -namespace { - -// Name of command-line flag to disable use of I444 by default. -const char kDisableI444SwitchName[] = "disable-i444"; - -} // namespace - ClientSession::ClientSession( EventHandler* event_handler, std::unique_ptr<protocol::ConnectionToClient> connection, @@ -71,11 +64,7 @@ disable_clipboard_filter_(clipboard_echo_filter_.host_filter()), client_clipboard_factory_(clipboard_echo_filter_.client_filter()), max_duration_(max_duration), - pairing_registry_(pairing_registry), - // Note that |lossless_video_color_| defaults to true, but actually only - // controls VP9 video stream color quality. - lossless_video_color_(!base::CommandLine::ForCurrentProcess()->HasSwitch( - kDisableI444SwitchName)) { + pairing_registry_(pairing_registry) { connection_->session()->AddPlugin(&host_experiment_session_plugin_); connection_->SetEventHandler(this);
diff --git a/services/device/public/cpp/test/test_wake_lock_provider.cc b/services/device/public/cpp/test/test_wake_lock_provider.cc index 5127229..543c4da 100644 --- a/services/device/public/cpp/test/test_wake_lock_provider.cc +++ b/services/device/public/cpp/test/test_wake_lock_provider.cc
@@ -10,7 +10,6 @@ #include "base/callback.h" #include "base/logging.h" #include "mojo/public/cpp/bindings/binding.h" -#include "mojo/public/cpp/bindings/strong_binding.h" #include "services/device/public/mojom/constants.mojom.h" namespace device { @@ -160,7 +159,7 @@ void TestWakeLockProvider::GetWakeLockContextForID( int context_id, - mojo::InterfaceRequest<mojom::WakeLockContext> request) { + mojo::PendingReceiver<mojom::WakeLockContext> receiver) { // This method is only used on Android. NOTIMPLEMENTED(); }
diff --git a/services/device/public/cpp/test/test_wake_lock_provider.h b/services/device/public/cpp/test/test_wake_lock_provider.h index e7e551d..f34fb9a 100644 --- a/services/device/public/cpp/test/test_wake_lock_provider.h +++ b/services/device/public/cpp/test/test_wake_lock_provider.h
@@ -39,7 +39,7 @@ // mojom::WakeLockProvider: void GetWakeLockContextForID( int context_id, - mojo::InterfaceRequest<mojom::WakeLockContext> request) override; + mojo::PendingReceiver<mojom::WakeLockContext> receiver) override; void GetWakeLockWithoutContext(mojom::WakeLockType type, mojom::WakeLockReason reason, const std::string& description,
diff --git a/services/device/public/mojom/wake_lock_provider.mojom b/services/device/public/mojom/wake_lock_provider.mojom index 4353391..2e89db96 100644 --- a/services/device/public/mojom/wake_lock_provider.mojom +++ b/services/device/public/mojom/wake_lock_provider.mojom
@@ -12,7 +12,8 @@ // Gets a WakeLockContext that is associated with |context_id|. |context_id| // is used to obtain the NativeView associated with the relevant context on // Android (see WakeLockContextCallback). |context_id| must be >= 0. - GetWakeLockContextForID(int32 context_id, WakeLockContext& context); + GetWakeLockContextForID(int32 context_id, + pending_receiver<WakeLockContext> context); // Gets a WakeLock outside of any context. This method can be used // if the client does not have any context available (e.g., is not
diff --git a/services/device/wake_lock/wake_lock_provider.cc b/services/device/wake_lock/wake_lock_provider.cc index a629a4c95..a50ef84 100644 --- a/services/device/wake_lock/wake_lock_provider.cc +++ b/services/device/wake_lock/wake_lock_provider.cc
@@ -8,7 +8,7 @@ #include <string> #include <utility> -#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "services/device/wake_lock/wake_lock.h" namespace device { @@ -56,12 +56,12 @@ void WakeLockProvider::GetWakeLockContextForID( int context_id, - mojom::WakeLockContextRequest request) { + mojo::PendingReceiver<mojom::WakeLockContext> receiver) { DCHECK_GE(context_id, 0); - mojo::MakeStrongBinding( + mojo::MakeSelfOwnedReceiver( std::make_unique<WakeLockContext>(context_id, file_task_runner_, native_view_getter_), - std::move(request)); + std::move(receiver)); } void WakeLockProvider::GetWakeLockWithoutContext(
diff --git a/services/device/wake_lock/wake_lock_provider.h b/services/device/wake_lock/wake_lock_provider.h index ac59e17..8d38ef7 100644 --- a/services/device/wake_lock/wake_lock_provider.h +++ b/services/device/wake_lock/wake_lock_provider.h
@@ -13,6 +13,7 @@ #include "base/single_thread_task_runner.h" #include "mojo/public/cpp/bindings/interface_ptr_set.h" #include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "services/device/public/mojom/wake_lock_context.mojom.h" #include "services/device/public/mojom/wake_lock_provider.mojom.h" #include "services/device/wake_lock/wake_lock.h" @@ -33,8 +34,9 @@ void AddBinding(mojom::WakeLockProviderRequest request); // mojom::WakeLockProvider overrides. - void GetWakeLockContextForID(int context_id, - mojom::WakeLockContextRequest request) override; + void GetWakeLockContextForID( + int context_id, + mojo::PendingReceiver<mojom::WakeLockContext> receiver) override; void GetWakeLockWithoutContext(mojom::WakeLockType type, mojom::WakeLockReason reason, const std::string& description,
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc index 7c8f861b..3b865bb 100644 --- a/services/network/restricted_cookie_manager_unittest.cc +++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -15,6 +15,7 @@ #include "mojo/core/embedder/embedder.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" #include "net/base/features.h" #include "net/cookies/canonical_cookie_test_helpers.h" #include "net/cookies/cookie_constants.h" @@ -171,9 +172,10 @@ false /* is_service_worker*/, kProcessId, kRoutingId)), - binding_(service_.get(), mojo::MakeRequest(&service_ptr_)) { + receiver_(service_.get(), + service_remote_.BindNewPipeAndPassReceiver()) { sync_service_ = - std::make_unique<RestrictedCookieManagerSync>(service_ptr_.get()); + std::make_unique<RestrictedCookieManagerSync>(service_remote_.get()); } ~RestrictedCookieManagerTest() override {} @@ -242,7 +244,7 @@ bool received_bad_message() { return received_bad_message_; } - mojom::RestrictedCookieManager* backend() { return service_ptr_.get(); } + mojom::RestrictedCookieManager* backend() { return service_remote_.get(); } protected: void OnBadMessage(const std::string& reason) { @@ -261,8 +263,8 @@ CookieSettings cookie_settings_; RecordingNetworkContextClient recording_client_; std::unique_ptr<RestrictedCookieManager> service_; - mojom::RestrictedCookieManagerPtr service_ptr_; - mojo::Binding<mojom::RestrictedCookieManager> binding_; + mojo::Remote<mojom::RestrictedCookieManager> service_remote_; + mojo::Receiver<mojom::RestrictedCookieManager> receiver_; std::unique_ptr<RestrictedCookieManagerSync> sync_service_; bool expecting_bad_message_ = false; bool received_bad_message_ = false;
diff --git a/sql/database.cc b/sql/database.cc index 3ef9c18d..d5b4b5bd 100644 --- a/sql/database.cc +++ b/sql/database.cc
@@ -36,6 +36,10 @@ #include "sql/vfs_wrapper.h" #include "third_party/sqlite/sqlite3.h" +#if defined(OS_WIN) +#include "base/win/file_pre_reader.h" +#endif + namespace { // Spin for up to a second waiting for the lock to clear when setting @@ -355,6 +359,9 @@ return; } +#if defined(OS_WIN) + base::win::PreReadFile(DbPath(), false); +#else // The constructor and set_page_size() ensure that page_size_ is never zero. const int page_size = page_size_; DCHECK(page_size); @@ -383,6 +390,7 @@ if (rc != SQLITE_OK) return; } +#endif } // SQLite keeps unused pages associated with a database in a cache. It asks
diff --git a/third_party/.gitignore b/third_party/.gitignore index 4a0d413a..a0870189 100644 --- a/third_party/.gitignore +++ b/third_party/.gitignore
@@ -130,6 +130,7 @@ /libexif/sources /libFuzzer/src /libprotobuf-mutator/src +/libipp/libipp /libjingle/source /libjpeg_turbo /liblouis/src
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn index 42d03e0..93f8748 100644 --- a/third_party/blink/public/BUILD.gn +++ b/third_party/blink/public/BUILD.gn
@@ -157,6 +157,7 @@ "platform/modules/mediastream/web_platform_media_stream_track.h", "platform/modules/mediastream/webrtc_uma_histograms.h", "platform/modules/peerconnection/audio_codec_factory.h", + "platform/modules/peerconnection/rtc_event_log_output_sink.h", "platform/modules/remoteplayback/web_remote_playback_client.h", "platform/modules/service_worker/web_service_worker_error.h", "platform/modules/service_worker/web_service_worker_network_provider.h",
diff --git a/third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom b/third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom index 8a1d0a5..f8880f4 100644 --- a/third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom +++ b/third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom
@@ -28,8 +28,7 @@ Update(uint32 player_id, viz.mojom.SurfaceId? surface_id, gfx.mojom.Size natural_size, - bool show_play_pause_button, - bool show_mute_button); + bool show_play_pause_button); // Request to stop the current session. It will close the Picture-in-Picture // window and make other calls related to the session no-ops. @@ -51,15 +50,12 @@ // natural_size: Size of the video frames. // show_play_pause_button: Whether a play/pause control should be offered in // the Picture-in-Picture window. - // show_mute_button: Whether a mute control should be offered in the - // Picture-in-Picture window. // observer: Observer to be associated with the session. StartSession( uint32 player_id, viz.mojom.SurfaceId? surface_id, gfx.mojom.Size natural_size, bool show_play_pause_button, - bool show_mute_button, pending_remote<PictureInPictureSessionObserver> observer) => (pending_remote<PictureInPictureSession>? session, gfx.mojom.Size size); };
diff --git a/third_party/blink/public/platform/mac/web_scrollbar_theme.h b/third_party/blink/public/platform/mac/web_scrollbar_theme.h index 9af5197c..0cfe437 100644 --- a/third_party/blink/public/platform/mac/web_scrollbar_theme.h +++ b/third_party/blink/public/platform/mac/web_scrollbar_theme.h
@@ -31,6 +31,7 @@ #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MAC_WEB_SCROLLBAR_THEME_H_ #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MAC_WEB_SCROLLBAR_THEME_H_ +#include "base/optional.h" #include "third_party/blink/public/platform/web_common.h" namespace blink { @@ -50,8 +51,8 @@ // |redraw| is true if the update requires a redraw to include the change. // |jump_on_track_click| is the current value of AppleScrollerPagingBehavior. BLINK_EXPORT static void UpdateScrollbarsWithNSDefaults( - float initial_button_delay, - float autoscroll_button_delay, + base::Optional<float> initial_button_delay, + base::Optional<float> autoscroll_button_delay, ScrollerStyle preferred_scroller_style, bool redraw, bool jump_on_track_click);
diff --git a/third_party/blink/public/platform/modules/peerconnection/rtc_event_log_output_sink.h b/third_party/blink/public/platform/modules/peerconnection/rtc_event_log_output_sink.h new file mode 100644 index 0000000..12b5371 --- /dev/null +++ b/third_party/blink/public/platform/modules/peerconnection/rtc_event_log_output_sink.h
@@ -0,0 +1,25 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_EVENT_LOG_OUTPUT_SINK_H_ +#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_EVENT_LOG_OUTPUT_SINK_H_ + +#include <string> + +#include "third_party/blink/public/platform/web_common.h" + +namespace blink { + +// TODO(crbug.com/787254): Move this class out of the Blink exposed API +// when all users of it have been Onion souped. +class BLINK_PLATFORM_EXPORT RtcEventLogOutputSink { + public: + virtual ~RtcEventLogOutputSink() = default; + + virtual void OnWebRtcEventLogWrite(const std::string& output) = 0; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_EVENT_LOG_OUTPUT_SINK_H_
diff --git a/third_party/blink/public/platform/web_rtc_rtp_source.h b/third_party/blink/public/platform/web_rtc_rtp_source.h index f90acbd..959440f 100644 --- a/third_party/blink/public/platform/web_rtc_rtp_source.h +++ b/third_party/blink/public/platform/web_rtc_rtp_source.h
@@ -12,6 +12,10 @@ class TimeTicks; } +namespace webrtc { +class RtpSource; +} + namespace blink { // Represents both SSRCs and CSRCs. @@ -33,6 +37,9 @@ virtual uint32_t RtpTimestamp() const = 0; }; +BLINK_PLATFORM_EXPORT std::unique_ptr<WebRTCRtpSource> CreateRTCRtpSource( + const webrtc::RtpSource& source); + } // namespace blink #endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_RTP_SOURCE_H_
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index 9e948d72..158fc92 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1259,6 +1259,7 @@ "html/html_link_element_test.cc", "html/html_meta_element_test.cc", "html/html_object_element_test.cc", + "html/html_plugin_element_test.cc", "html/html_slot_element_test.cc", "html/html_table_row_element_test.cc", "html/image_document_test.cc",
diff --git a/third_party/blink/renderer/core/events/promise_rejection_event.cc b/third_party/blink/renderer/core/events/promise_rejection_event.cc index d8cfbb6..1c974474 100644 --- a/third_party/blink/renderer/core/events/promise_rejection_event.cc +++ b/third_party/blink/renderer/core/events/promise_rejection_event.cc
@@ -25,14 +25,6 @@ PromiseRejectionEvent::~PromiseRejectionEvent() = default; -void PromiseRejectionEvent::Dispose() { - // Clear ScopedPersistents so that V8 doesn't call phantom callbacks - // (and touch the ScopedPersistents) after Oilpan starts lazy sweeping. - promise_.Clear(); - reason_.Clear(); - world_ = nullptr; -} - ScriptPromise PromiseRejectionEvent::promise(ScriptState* script_state) const { // Return null when the promise is accessed by a different world than the // world that created the promise. @@ -57,7 +49,8 @@ bool PromiseRejectionEvent::CanBeDispatchedInWorld( const DOMWrapperWorld& world) const { - return world_ && world_->GetWorldId() == world.GetWorldId(); + DCHECK(world_); + return world_->GetWorldId() == world.GetWorldId(); } void PromiseRejectionEvent::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/events/promise_rejection_event.h b/third_party/blink/renderer/core/events/promise_rejection_event.h index afcc54a..78786ef7 100644 --- a/third_party/blink/renderer/core/events/promise_rejection_event.h +++ b/third_party/blink/renderer/core/events/promise_rejection_event.h
@@ -18,7 +18,6 @@ class CORE_EXPORT PromiseRejectionEvent final : public Event { DEFINE_WRAPPERTYPEINFO(); - USING_PRE_FINALIZER(PromiseRejectionEvent, Dispose); public: static PromiseRejectionEvent* Create( @@ -46,7 +45,6 @@ private: ~PromiseRejectionEvent() override; - void Dispose(); scoped_refptr<DOMWrapperWorld> world_; TraceWrapperV8Reference<v8::Value> promise_;
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 73b7574..08dfb2ee 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -3455,6 +3455,11 @@ plugins_.insert(plugin); } +void LocalFrameView::RemovePlugin(WebPluginContainerImpl* plugin) { + DCHECK(plugins_.Contains(plugin)); + plugins_.erase(plugin); +} + void LocalFrameView::RemoveScrollbar(Scrollbar* scrollbar) { DCHECK(scrollbars_.Contains(scrollbar)); scrollbars_.erase(scrollbar);
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index 0c895d0b..5a4238d 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -492,6 +492,7 @@ using PluginSet = HeapHashSet<Member<WebPluginContainerImpl>>; const PluginSet& Plugins() const { return plugins_; } void AddPlugin(WebPluginContainerImpl*); + void RemovePlugin(WebPluginContainerImpl*); // Custom scrollbars in PaintLayerScrollableArea need to be called with // StyleChanged whenever window focus is changed. void RemoveScrollbar(Scrollbar*);
diff --git a/third_party/blink/renderer/core/frame/use_counter_helper.cc b/third_party/blink/renderer/core/frame/use_counter_helper.cc index 6d903fe..6038cd2 100644 --- a/third_party/blink/renderer/core/frame/use_counter_helper.cc +++ b/third_party/blink/renderer/core/frame/use_counter_helper.cc
@@ -25,7 +25,6 @@ #include "third_party/blink/renderer/core/frame/use_counter_helper.h" -#include "third_party/blink/public/mojom/use_counter/css_property_id.mojom-blink.h" #include "third_party/blink/renderer/core/css/css_style_sheet.h" #include "third_party/blink/renderer/core/css/style_sheet_contents.h" #include "third_party/blink/renderer/core/dom/document.h"
diff --git a/third_party/blink/renderer/core/frame/use_counter_helper.h b/third_party/blink/renderer/core/frame/use_counter_helper.h index 00e7d69..6c12e3e 100644 --- a/third_party/blink/renderer/core/frame/use_counter_helper.h +++ b/third_party/blink/renderer/core/frame/use_counter_helper.h
@@ -28,6 +28,7 @@ #include <bitset> #include "base/macros.h" +#include "third_party/blink/public/mojom/use_counter/css_property_id.mojom-blink.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/css/css_property_names.h" #include "third_party/blink/renderer/core/css/parser/css_parser_mode.h" @@ -163,13 +164,10 @@ std::bitset<static_cast<size_t>(WebFeature::kNumberOfFeatures)> features_recorded_; - // TODO(majidvp): Use CSSSampleId::kMaxValue here. We insert CSSSampleId into - // this bitset so max value should reflect that. At the moment - // numCSSPropertyIDs (currently 995) is larger than CSSSampleId:kMaxValue - // (currently 645) so while inefficient it is safe to use but this can change - // in future. - std::bitset<numCSSPropertyIDs> css_recorded_; - std::bitset<numCSSPropertyIDs> animated_css_recorded_; + static constexpr size_t kMaxSample = + static_cast<size_t>(mojom::CSSSampleId::kMaxValue) + 1; + std::bitset<kMaxSample> css_recorded_; + std::bitset<kMaxSample> animated_css_recorded_; HeapHashSet<Member<Observer>> observers_;
diff --git a/third_party/blink/renderer/core/html/html_plugin_element.cc b/third_party/blink/renderer/core/html/html_plugin_element.cc index ee41419..52dba9c 100644 --- a/third_party/blink/renderer/core/html/html_plugin_element.cc +++ b/third_party/blink/renderer/core/html/html_plugin_element.cc
@@ -312,6 +312,7 @@ if (!performing_reattach) SetDisposeView(); + RemovePluginFromFrameView(plugin); ResetInstance(); HTMLFrameOwnerElement::DetachLayoutTree(performing_reattach); @@ -626,7 +627,9 @@ loaded_url_ = url; if (persisted_plugin_) { + auto* plugin = persisted_plugin_.Get(); SetEmbeddedContentView(persisted_plugin_.Release()); + layout_object->GetFrameView()->AddPlugin(plugin); } else { bool load_manually = GetDocument().IsPluginDocument() && !GetDocument().ContainsPlugins(); @@ -634,7 +637,7 @@ *this, url, plugin_params.Names(), plugin_params.Values(), mime_type, load_manually); if (!plugin) { - if (layout_object && !layout_object->ShowsUnavailablePluginIndicator()) { + if (!layout_object->ShowsUnavailablePluginIndicator()) { plugin_is_available_ = false; layout_object->SetPluginAvailability( LayoutEmbeddedObject::kPluginMissing); @@ -642,12 +645,8 @@ return false; } - if (layout_object) { - SetEmbeddedContentView(plugin); - layout_object->GetFrameView()->AddPlugin(plugin); - } else { - SetPersistedPlugin(plugin); - } + SetEmbeddedContentView(plugin); + layout_object->GetFrameView()->AddPlugin(plugin); } GetDocument().SetContainsPlugins(); @@ -722,6 +721,25 @@ return true; } +void HTMLPlugInElement::RemovePluginFromFrameView( + WebPluginContainerImpl* plugin) { + if (!plugin) + return; + + auto* layout_object = GetLayoutEmbeddedObject(); + if (!layout_object) + return; + + auto* frame_view = layout_object->GetFrameView(); + if (!frame_view) + return; + + if (!frame_view->Plugins().Contains(plugin)) + return; + + frame_view->RemovePlugin(plugin); +} + void HTMLPlugInElement::DidAddUserAgentShadowRoot(ShadowRoot&) { UserAgentShadowRoot()->AppendChild( HTMLSlotElement::CreateUserAgentDefaultSlot(GetDocument()));
diff --git a/third_party/blink/renderer/core/html/html_plugin_element.h b/third_party/blink/renderer/core/html/html_plugin_element.h index 053689c9..7d19199 100644 --- a/third_party/blink/renderer/core/html/html_plugin_element.h +++ b/third_party/blink/renderer/core/html/html_plugin_element.h
@@ -200,6 +200,7 @@ bool AllowedToLoadPlugin(const KURL&, const String& mime_type); // Perform checks based on the URL and MIME-type of the object to load. bool AllowedToLoadObject(const KURL&, const String& mime_type); + void RemovePluginFromFrameView(WebPluginContainerImpl* plugin); enum class ObjectContentType { kNone,
diff --git a/third_party/blink/renderer/core/html/html_plugin_element_test.cc b/third_party/blink/renderer/core/html/html_plugin_element_test.cc new file mode 100644 index 0000000..295f95d --- /dev/null +++ b/third_party/blink/renderer/core/html/html_plugin_element_test.cc
@@ -0,0 +1,138 @@ +// Copyright 2019 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/html/html_plugin_element.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/web/web_plugin_params.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h" +#include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/loader/empty_clients.h" +#include "third_party/blink/renderer/core/testing/fake_web_plugin.h" +#include "third_party/blink/renderer/core/testing/page_test_base.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +namespace { + +class TestPluginLocalFrameClient : public EmptyLocalFrameClient { + public: + TestPluginLocalFrameClient() = default; + + int plugin_created_count() const { return plugin_created_count_; } + + private: + std::unique_ptr<WebURLLoaderFactory> CreateURLLoaderFactory() override { + return Platform::Current()->CreateDefaultURLLoaderFactory(); + } + + WebPluginContainerImpl* CreatePlugin(HTMLPlugInElement& element, + const KURL& url, + const Vector<String>& param_names, + const Vector<String>& param_values, + const String& mime_type, + bool load_manually) override { + ++plugin_created_count_; + + // Based on LocalFrameClientImpl::CreatePlugin + WebPluginParams params; + params.url = url; + params.mime_type = mime_type; + params.attribute_names = param_names; + params.attribute_values = param_values; + params.load_manually = load_manually; + + WebPlugin* web_plugin = new FakeWebPlugin(params); + if (!web_plugin) + return nullptr; + + // The container takes ownership of the WebPlugin. + auto* container = + MakeGarbageCollected<WebPluginContainerImpl>(element, web_plugin); + + if (!web_plugin->Initialize(container)) + return nullptr; + + if (!element.GetLayoutObject()) + return nullptr; + + return container; + } + + int plugin_created_count_ = 0; +}; + +} // namespace + +class HTMLPlugInElementTest : public PageTestBase, + public testing::WithParamInterface<const char*> { + protected: + void SetUp() final { + frame_client_ = MakeGarbageCollected<TestPluginLocalFrameClient>(); + PageTestBase::SetupPageWithClients(nullptr, frame_client_, nullptr); + GetFrame().GetSettings()->SetPluginsEnabled(true); + } + + void TearDown() final { + PageTestBase::TearDown(); + frame_client_ = nullptr; + } + + LocalFrameView& GetFrameView() const { + return GetDummyPageHolder().GetFrameView(); + } + + int plugin_created_count() const { + return frame_client_->plugin_created_count(); + } + + private: + Persistent<TestPluginLocalFrameClient> frame_client_; +}; + +INSTANTIATE_TEST_SUITE_P(, + HTMLPlugInElementTest, + testing::Values("embed", "object")); + +TEST_P(HTMLPlugInElementTest, RemovePlugin) { + constexpr char kDivWithPlugin[] = R"HTML( + <div> + <%s id='test_plugin' + type='application/x-test-plugin' + src='test_plugin'> + </%s> + </div> + )HTML"; + + const char* container_type = GetParam(); + GetDocument().body()->SetInnerHTMLFromString( + String::Format(kDivWithPlugin, container_type, container_type)); + + auto* plugin = + ToHTMLPlugInElement(GetDocument().getElementById("test_plugin")); + ASSERT_TRUE(plugin); + EXPECT_EQ(container_type, plugin->tagName().LowerASCII()); + + UpdateAllLifecyclePhasesForTest(); + plugin->UpdatePlugin(); + + EXPECT_EQ(1, plugin_created_count()); + + auto* owned_plugin = plugin->OwnedPlugin(); + ASSERT_TRUE(owned_plugin); + + EXPECT_EQ(1u, GetFrameView().Plugins().size()); + ASSERT_TRUE(GetFrameView().Plugins().Contains(owned_plugin)); + + plugin->parentNode()->removeChild(plugin); + EXPECT_FALSE(GetDocument().HasElementWithId("test_plugin")); + + UpdateAllLifecyclePhasesForTest(); + EXPECT_EQ(0u, GetFrameView().Plugins().size()); + EXPECT_FALSE(GetFrameView().Plugins().Contains(owned_plugin)); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc b/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc index 189922e..6a2d579 100644 --- a/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc +++ b/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc
@@ -38,8 +38,7 @@ void Update(uint32_t player_id, const base::Optional<viz::SurfaceId>&, const blink::WebSize&, - bool show_play_pause_button, - bool show_mute_button) final {} + bool show_play_pause_button) final {} private: mojo::Receiver<mojom::blink::PictureInPictureSession> receiver_; @@ -64,7 +63,6 @@ const base::Optional<viz::SurfaceId>&, const blink::WebSize&, bool, - bool, mojo::PendingRemote<mojom::blink::PictureInPictureSessionObserver>, StartSessionCallback callback) final { mojo::PendingRemote<mojom::blink::PictureInPictureSession> session_remote;
diff --git a/third_party/blink/renderer/core/loader/cookie_jar.cc b/third_party/blink/renderer/core/loader/cookie_jar.cc index 5bb98eac..2f68fd3c 100644 --- a/third_party/blink/renderer/core/loader/cookie_jar.cc +++ b/third_party/blink/renderer/core/loader/cookie_jar.cc
@@ -52,9 +52,10 @@ } void CookieJar::RequestRestrictedCookieManagerIfNeeded() { - if (!backend_.is_bound() || backend_.encountered_error()) { + if (!backend_.is_bound() || !backend_.is_connected()) { + backend_.reset(); document_->GetInterfaceProvider()->GetInterface( - mojo::MakeRequest(&backend_)); + backend_.BindNewPipeAndPassReceiver()); } }
diff --git a/third_party/blink/renderer/core/loader/cookie_jar.h b/third_party/blink/renderer/core/loader/cookie_jar.h index bd2fd5a..f1602d1 100644 --- a/third_party/blink/renderer/core/loader/cookie_jar.h +++ b/third_party/blink/renderer/core/loader/cookie_jar.h
@@ -7,6 +7,7 @@ #include "services/network/public/mojom/restricted_cookie_manager.mojom-blink.h" +#include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -25,7 +26,7 @@ private: void RequestRestrictedCookieManagerIfNeeded(); - network::mojom::blink::RestrictedCookieManagerPtr backend_; + mojo::Remote<network::mojom::blink::RestrictedCookieManager> backend_; WeakPersistent<blink::Document> document_; // Document owns |this|. };
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc index f630930..410c9ee 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -1647,8 +1647,15 @@ orientation == kVerticalScrollbar); } +bool PaintLayerScrollableArea::HasOverflowControls() const { + // We do not need to check for ScrollCorner because it only exists iff there + // are scrollbars, see: |ScrollCornerRect| and |UpdateScrollCornerStyle|. + DCHECK(!ScrollCorner() || HasScrollbar()); + return HasScrollbar() || GetLayoutBox()->CanResize(); +} + void PaintLayerScrollableArea::PositionOverflowControls() { - if (!HasOverflowControls() && !GetLayoutBox()->CanResize()) + if (!HasOverflowControls()) return; const IntRect border_box = @@ -1660,9 +1667,8 @@ if (Scrollbar* horizontal_scrollbar = HorizontalScrollbar()) horizontal_scrollbar->SetFrameRect(RectForHorizontalScrollbar(border_box)); - const IntRect& scroll_corner = ScrollCornerRect(); if (scroll_corner_) - scroll_corner_->SetFrameRect(LayoutRect(scroll_corner)); + scroll_corner_->SetFrameRect(LayoutRect(ScrollCornerRect())); if (resizer_) resizer_->SetFrameRect( @@ -1704,7 +1710,7 @@ bool PaintLayerScrollableArea::HitTestOverflowControls( HitTestResult& result, const IntPoint& local_point) { - if (!HasScrollbar() && !GetLayoutBox()->CanResize()) + if (!HasOverflowControls()) return false; IntRect resize_control_rect;
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h index d3aa31c..786664f 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -377,9 +377,11 @@ bool HasScrollbar() const { return HasHorizontalScrollbar() || HasVerticalScrollbar(); } - bool HasOverflowControls() const { - return HasScrollbar() || ScrollCorner() || Resizer(); - } + // Overflow controls are scrollbars, scroll corners, and resizers. The + // |scroll_corner_| and |resizer_| scrollbar parts are only created for + // specific pseudo styles but there can still be a scroll corner control or + // resize control without these custom styled scrollbar parts. + bool HasOverflowControls() const; bool HasOverflow() const { return HasHorizontalOverflow() || HasVerticalOverflow(); }
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h index 11cf27e..0365d27 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h +++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h
@@ -95,8 +95,8 @@ // See WebScrollbarTheme for parameters description. static void UpdateScrollbarsWithNSDefaults( - float initial_button_delay, - float autoscroll_button_delay, + base::Optional<float> initial_button_delay, + base::Optional<float> autoscroll_button_delay, NSScrollerStyle preferred_scroller_style, bool redraw, bool jump_on_track_click);
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm index 6219cb1..b1bdc89 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm +++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
@@ -415,13 +415,15 @@ // static void ScrollbarThemeMac::UpdateScrollbarsWithNSDefaults( - float initial_button_delay, - float autoscroll_button_delay, + base::Optional<float> initial_button_delay, + base::Optional<float> autoscroll_button_delay, NSScrollerStyle preferred_scroller_style, bool redraw, bool jump_on_track_click) { - s_initial_button_delay = initial_button_delay; - s_autoscroll_button_delay = autoscroll_button_delay; + s_initial_button_delay = + initial_button_delay.value_or(s_initial_button_delay); + s_autoscroll_button_delay = + autoscroll_button_delay.value_or(s_autoscroll_button_delay); s_preferred_scroller_style = preferred_scroller_style; s_jump_on_track_click = jump_on_track_click; if (redraw) {
diff --git a/third_party/blink/renderer/core/scroll/web_scrollbar_theme.mm b/third_party/blink/renderer/core/scroll/web_scrollbar_theme.mm index 55530f5..bde3fec 100644 --- a/third_party/blink/renderer/core/scroll/web_scrollbar_theme.mm +++ b/third_party/blink/renderer/core/scroll/web_scrollbar_theme.mm
@@ -45,8 +45,8 @@ "ScrollerStyleOverlay must match NSScrollerStyleOverlay"); void WebScrollbarTheme::UpdateScrollbarsWithNSDefaults( - float initial_button_delay, - float autoscroll_button_delay, + base::Optional<float> initial_button_delay, + base::Optional<float> autoscroll_button_delay, ScrollerStyle preferred_scroller_style, bool redraw, bool jump_on_track_click) {
diff --git a/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js b/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js index 6ae3f07..8a95859 100644 --- a/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js +++ b/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js
@@ -160,7 +160,7 @@ * @param {string} origin */ clearForOrigin(origin) { - if (!this._enabled) + if (!this._enabled || !this._databaseNamesBySecurityOrigin[origin]) return; this._removeOrigin(origin);
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc index 47a43c3c..3585a84 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc +++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
@@ -456,7 +456,7 @@ CookieStore::CookieStore( ExecutionContext* execution_context, - network::mojom::blink::RestrictedCookieManagerPtr backend, + mojo::Remote<network::mojom::blink::RestrictedCookieManager> backend, mojo::Remote<blink::mojom::blink::CookieStore> subscription_backend) : ContextLifecycleObserver(execution_context), backend_(std::move(backend)),
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.h b/third_party/blink/renderer/modules/cookie_store/cookie_store.h index 606218e..d85631f 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_store.h +++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.h
@@ -37,9 +37,10 @@ public: CookieStore( ExecutionContext*, - network::mojom::blink::RestrictedCookieManagerPtr backend, + mojo::Remote<network::mojom::blink::RestrictedCookieManager> backend, mojo::Remote<blink::mojom::blink::CookieStore> subscription_backend); - // Needed because of the network::mojom::blink::RestrictedCookieManagerPtr + // Needed because of the + // mojo::Remote<network::mojom::blink::RestrictedCookieManager> ~CookieStore() override; ScriptPromise getAll(ScriptState*, const String& name, ExceptionState&); @@ -146,7 +147,7 @@ void StopObserving(); // Wraps an always-on Mojo pipe for sending requests to the Network Service. - network::mojom::blink::RestrictedCookieManagerPtr backend_; + mojo::Remote<network::mojom::blink::RestrictedCookieManager> backend_; // Wraps a Mojo pipe for managing service worker cookie change subscriptions. //
diff --git a/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.cc index daeaadc..586f5394 100644 --- a/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.cc +++ b/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.cc
@@ -19,18 +19,18 @@ CookieStore* GlobalCookieStoreImpl<WorkerGlobalScope>::BuildCookieStore( ExecutionContext* execution_context, service_manager::InterfaceProvider* interface_provider) { - network::mojom::blink::RestrictedCookieManagerPtr cookie_manager_ptr; - interface_provider->GetInterface(mojo::MakeRequest( - &cookie_manager_ptr, - execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI))); - + mojo::Remote<network::mojom::blink::RestrictedCookieManager> + cookie_manager_remote; + interface_provider->GetInterface( + cookie_manager_remote.BindNewPipeAndPassReceiver( + execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI))); mojo::Remote<blink::mojom::blink::CookieStore> cookie_store_remote; interface_provider->GetInterface( cookie_store_remote.BindNewPipeAndPassReceiver( execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI))); return MakeGarbageCollected<CookieStore>(execution_context, - std::move(cookie_manager_ptr), + std::move(cookie_manager_remote), std::move(cookie_store_remote)); }
diff --git a/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc index bae54f40..666e592 100644 --- a/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc +++ b/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc
@@ -19,13 +19,14 @@ CookieStore* GlobalCookieStoreImpl<LocalDOMWindow>::BuildCookieStore( ExecutionContext* execution_context, service_manager::InterfaceProvider* interface_provider) { - network::mojom::blink::RestrictedCookieManagerPtr cookie_manager_ptr; + mojo::Remote<network::mojom::blink::RestrictedCookieManager> + cookie_manager_remote; // See https://bit.ly/2S0zRAS for task types. - interface_provider->GetInterface(mojo::MakeRequest( - &cookie_manager_ptr, - execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI))); + interface_provider->GetInterface( + cookie_manager_remote.BindNewPipeAndPassReceiver( + execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI))); return MakeGarbageCollected<CookieStore>( - execution_context, std::move(cookie_manager_ptr), + execution_context, std::move(cookie_manager_remote), mojo::Remote<blink::mojom::blink::CookieStore>()); }
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc index d594908..b5490ca 100644 --- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc +++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -177,8 +177,7 @@ video_element->GetWebMediaPlayer()->GetDelegateId(), video_element->GetWebMediaPlayer()->GetSurfaceId(), video_element->GetWebMediaPlayer()->NaturalSize(), - ShouldShowPlayPauseButton(*video_element), - ShouldShowMuteButton(*video_element), std::move(session_observer), + ShouldShowPlayPauseButton(*video_element), std::move(session_observer), WTF::Bind(&PictureInPictureControllerImpl::OnEnteredPictureInPicture, WrapPersistent(this), WrapPersistent(video_element), WrapPersistent(resolver))); @@ -386,8 +385,7 @@ picture_in_picture_element_->GetWebMediaPlayer()->GetDelegateId(), picture_in_picture_element_->GetWebMediaPlayer()->GetSurfaceId(), picture_in_picture_element_->GetWebMediaPlayer()->NaturalSize(), - ShouldShowPlayPauseButton(*picture_in_picture_element_), - ShouldShowMuteButton(*picture_in_picture_element_)); + ShouldShowPlayPauseButton(*picture_in_picture_element_)); } void PictureInPictureControllerImpl::OnWindowSizeChanged( @@ -400,13 +398,6 @@ OnExitedPictureInPicture(nullptr); } -bool PictureInPictureControllerImpl::ShouldShowMuteButton( - const HTMLVideoElement& element) { - DCHECK(GetSupplementable()); - return element.HasAudio() && RuntimeEnabledFeatures::MuteButtonEnabled( - GetSupplementable()->GetExecutionContext()); -} - void PictureInPictureControllerImpl::Trace(blink::Visitor* visitor) { visitor->Trace(picture_in_picture_element_); visitor->Trace(auto_picture_in_picture_elements_);
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h index 46ad6ac..916fcc2 100644 --- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h +++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
@@ -116,10 +116,6 @@ // initialized successfully. bool EnsureService(); - // Returns true if video has an audio track and if MuteButton origin trial is - // enabled. Otherwise it returns false. - bool ShouldShowMuteButton(const HTMLVideoElement& element); - // The Picture-in-Picture element for the associated document. Member<HTMLVideoElement> picture_in_picture_element_;
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc index 65e4c812..169a910 100644 --- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc +++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc
@@ -44,11 +44,10 @@ ~MockPictureInPictureSession() override = default; MOCK_METHOD1(Stop, void(StopCallback)); - MOCK_METHOD5(Update, + MOCK_METHOD4(Update, void(uint32_t, const base::Optional<viz::SurfaceId>&, const blink::WebSize&, - bool, bool)); private: @@ -63,7 +62,7 @@ public: MockPictureInPictureService() { // Setup default implementations. - ON_CALL(*this, StartSession(_, _, _, _, _, _, _)) + ON_CALL(*this, StartSession(_, _, _, _, _, _)) .WillByDefault(testing::Invoke( this, &MockPictureInPictureService::StartSessionInternal)); } @@ -77,13 +76,12 @@ session_remote_.InitWithNewPipeAndPassReceiver())); } - MOCK_METHOD7( + MOCK_METHOD6( StartSession, void(uint32_t, const base::Optional<viz::SurfaceId>&, const blink::WebSize&, bool, - bool, mojo::PendingRemote<mojom::blink::PictureInPictureSessionObserver>, StartSessionCallback)); @@ -94,7 +92,6 @@ const base::Optional<viz::SurfaceId>&, const blink::WebSize&, bool, - bool, mojo::PendingRemote<mojom::blink::PictureInPictureSessionObserver>, StartSessionCallback callback) { std::move(callback).Run(std::move(session_remote_), WebSize()); @@ -203,7 +200,7 @@ WebMediaPlayer* player = Video()->GetWebMediaPlayer(); EXPECT_CALL(Service(), StartSession(player->GetDelegateId(), player->GetSurfaceId(), - player->NaturalSize(), true, false, _, _)); + player->NaturalSize(), true, _, _)); PictureInPictureControllerImpl::From(GetDocument()) .EnterPictureInPicture(Video(), nullptr /* options */, @@ -223,7 +220,7 @@ WebMediaPlayer* player = Video()->GetWebMediaPlayer(); EXPECT_CALL(Service(), StartSession(player->GetDelegateId(), player->GetSurfaceId(), - player->NaturalSize(), true, false, _, _)); + player->NaturalSize(), true, _, _)); PictureInPictureControllerImpl::From(GetDocument()) .EnterPictureInPicture(Video(), nullptr /* options */, @@ -251,7 +248,7 @@ WebMediaPlayer* player = Video()->GetWebMediaPlayer(); EXPECT_CALL(Service(), StartSession(player->GetDelegateId(), player->GetSurfaceId(), - player->NaturalSize(), true, false, _, _)); + player->NaturalSize(), true, _, _)); PictureInPictureControllerImpl::From(GetDocument()) .EnterPictureInPicture(Video(), nullptr /* options */, @@ -271,7 +268,7 @@ WebMediaPlayer* player = Video()->GetWebMediaPlayer(); EXPECT_CALL(Service(), StartSession(player->GetDelegateId(), player->GetSurfaceId(), - player->NaturalSize(), true, false, _, _)); + player->NaturalSize(), true, _, _)); PictureInPictureControllerImpl::From(GetDocument()) .EnterPictureInPicture(Video(), nullptr /* options */, @@ -300,7 +297,7 @@ WebMediaPlayer* player = Video()->GetWebMediaPlayer(); EXPECT_CALL(Service(), StartSession(player->GetDelegateId(), player->GetSurfaceId(), - player->NaturalSize(), false, false, _, _)); + player->NaturalSize(), false, _, _)); PictureInPictureControllerImpl::From(GetDocument()) .EnterPictureInPicture(Video(), nullptr /* options */, @@ -320,7 +317,7 @@ WebMediaPlayer* player = Video()->GetWebMediaPlayer(); EXPECT_CALL(Service(), StartSession(player->GetDelegateId(), player->GetSurfaceId(), - player->NaturalSize(), false, false, _, _)); + player->NaturalSize(), false, _, _)); PictureInPictureControllerImpl::From(GetDocument()) .EnterPictureInPicture(Video(), nullptr /* options */,
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc index 10f9d5b..e63e66d 100644 --- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc +++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -86,6 +86,10 @@ template <> DawnTextureFormat AsDawnEnum<DawnTextureFormat>( const WTF::String& webgpu_enum) { + if (webgpu_enum.IsNull()) { + return DAWN_TEXTURE_FORMAT_NONE; + } + // Normal 8 bit formats if (webgpu_enum == "r8unorm") { return DAWN_TEXTURE_FORMAT_R8_UNORM; @@ -231,6 +235,9 @@ template <> DawnTextureViewDimension AsDawnEnum<DawnTextureViewDimension>( const WTF::String& webgpu_enum) { + if (webgpu_enum.IsNull()) { + return DAWN_TEXTURE_VIEW_DIMENSION_NONE; + } if (webgpu_enum == "2d") { return DAWN_TEXTURE_VIEW_DIMENSION_2D; }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc index 0fda998..859082c 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
@@ -17,7 +17,7 @@ dawn_binding.binding = webgpu_binding->binding(); dawn_binding.type = AsDawnEnum<DawnBindingType>(webgpu_binding->type()); dawn_binding.visibility = - AsDawnEnum<DawnShaderStageBit>(webgpu_binding->visibility()); + AsDawnEnum<DawnShaderStage>(webgpu_binding->visibility()); dawn_binding.textureComponentType = AsDawnEnum<DawnTextureComponentType>( webgpu_binding->textureComponentType()); dawn_binding.multisampled = webgpu_binding->multisampled();
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc b/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc index 79a4656..4c9c1951 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
@@ -49,7 +49,7 @@ DawnBufferDescriptor dawn_desc = {}; dawn_desc.nextInChain = nullptr; - dawn_desc.usage = AsDawnEnum<DawnBufferUsageBit>(webgpu_desc->usage()); + dawn_desc.usage = AsDawnEnum<DawnBufferUsage>(webgpu_desc->usage()); dawn_desc.size = webgpu_desc->size(); return dawn_desc;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc index a46cfae0..a400bf0e 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc
@@ -23,7 +23,7 @@ : DawnObjectBase(descriptor->device()->GetDawnControlClient()), device_(descriptor->device()), context_(context), - usage_(AsDawnEnum<DawnTextureUsageBit>(descriptor->usage())) { + usage_(AsDawnEnum<DawnTextureUsage>(descriptor->usage())) { swap_buffers_ = base::AdoptRef(new WebGPUSwapBufferProvider( this, GetDawnControlClient(), usage_, AsDawnEnum<DawnTextureFormat>(descriptor->format())));
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h index dcd998c4..b644bba9 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h +++ b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h
@@ -48,7 +48,7 @@ Member<GPUDevice> device_; Member<GPUCanvasContext> context_; - DawnTextureUsageBit usage_; + DawnTextureUsage usage_; Member<GPUTexture> texture_; };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc index 87e82db3..6006899d 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
@@ -19,7 +19,7 @@ DawnTextureDescriptor dawn_desc = {}; dawn_desc.nextInChain = nullptr; - dawn_desc.usage = static_cast<DawnTextureUsageBit>(webgpu_desc->usage()); + dawn_desc.usage = static_cast<DawnTextureUsage>(webgpu_desc->usage()); dawn_desc.dimension = AsDawnEnum<DawnTextureDimension>(webgpu_desc->dimension()); dawn_desc.size = AsDawnType(webgpu_desc->size()); @@ -81,11 +81,6 @@ device_, GetProcs().textureCreateView(GetHandle(), &dawn_desc)); } -GPUTextureView* GPUTexture::createDefaultView() { - return GPUTextureView::Create( - device_, GetProcs().textureCreateDefaultView(GetHandle())); -} - void GPUTexture::destroy() { GetProcs().textureDestroy(GetHandle()); }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.h b/third_party/blink/renderer/modules/webgpu/gpu_texture.h index 95acb2a2..2063c41 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_texture.h +++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.h
@@ -24,7 +24,6 @@ // gpu_texture.idl GPUTextureView* createView(const GPUTextureViewDescriptor* webgpu_desc); - GPUTextureView* createDefaultView(); void destroy(); private:
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture.idl index 0049a47..cdbcb36 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_texture.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
@@ -7,7 +7,6 @@ [ RuntimeEnabled=WebGPU ] interface GPUTexture { - GPUTextureView createView(GPUTextureViewDescriptor desc); - GPUTextureView createDefaultView(); + GPUTextureView createView(optional GPUTextureViewDescriptor desc); void destroy(); };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl index dda055b..551d292 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl
@@ -5,13 +5,13 @@ // https://gpuweb.github.io/gpuweb/ dictionary GPUTextureViewDescriptor { - required GPUTextureFormat format; - required GPUTextureViewDimension dimension; - required GPUTextureAspect aspect; + GPUTextureFormat format; + GPUTextureViewDimension dimension; + GPUTextureAspect aspect = "all"; unsigned long baseMipLevel = 0; - unsigned long mipLevelCount = 1; + unsigned long mipLevelCount = 0; unsigned long baseArrayLayer = 0; - unsigned long arrayLayerCount = 1; + unsigned long arrayLayerCount = 0; }; enum GPUTextureViewDimension {
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index ac3c0c7d..a0078a1e 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1231,6 +1231,8 @@ "peerconnection/rtc_dtmf_sender_handler.cc", "peerconnection/rtc_dtmf_sender_handler.h", "peerconnection/rtc_offer_options_platform.h", + "peerconnection/rtc_rtp_source.cc", + "peerconnection/rtc_rtp_source.h", "peerconnection/rtc_session_description_request.h", "peerconnection/rtc_stats_request.h", "peerconnection/rtc_stats_response_base.h",
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc index fc376069..7681d87d 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
@@ -29,7 +29,7 @@ WebGPUSwapBufferProvider::WebGPUSwapBufferProvider( Client* client, scoped_refptr<DawnControlClientHolder> dawn_control_client, - DawnTextureUsageBit usage, + DawnTextureUsage usage, DawnTextureFormat format) : dawn_control_client_(dawn_control_client), client_(client),
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h index 83711044..5d2a866 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
@@ -35,7 +35,7 @@ WebGPUSwapBufferProvider( Client* client, scoped_refptr<DawnControlClientHolder> dawn_control_client, - DawnTextureUsageBit usage, + DawnTextureUsage usage, DawnTextureFormat format); ~WebGPUSwapBufferProvider() override; @@ -84,7 +84,7 @@ scoped_refptr<cc::TextureLayer> layer_; bool neutered_ = false; - DawnTextureUsageBit usage_; + DawnTextureUsage usage_; uint32_t wire_texture_id_ = 0; uint32_t wire_texture_generation_ = 0;
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc index ee3e046..9e99fc6 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
@@ -58,7 +58,7 @@ bool* alive, Client* client, scoped_refptr<DawnControlClientHolder> dawn_control_client, - DawnTextureUsageBit usage, + DawnTextureUsage usage, DawnTextureFormat format) : WebGPUSwapBufferProvider(client, dawn_control_client, usage, format), alive_(alive) {} @@ -84,8 +84,7 @@ base::MakeRefCounted<DawnControlClientHolder>(std::move(provider)); provider_ = base::MakeRefCounted<WebGPUSwapBufferProviderForTests>( &provider_alive_, &client_, dawn_control_client_, - DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT, - DAWN_TEXTURE_FORMAT_RGBA8_UNORM); + DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT, DAWN_TEXTURE_FORMAT_RGBA8_UNORM); } scoped_refptr<DawnControlClientHolder> dawn_control_client_;
diff --git a/content/renderer/media/webrtc/rtc_rtp_source.cc b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.cc similarity index 74% rename from content/renderer/media/webrtc/rtc_rtp_source.cc rename to third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.cc index 308f39f..7169cc9 100644 --- a/content/renderer/media/webrtc/rtc_rtp_source.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/media/webrtc/rtc_rtp_source.h" +#include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h" #include <cmath> @@ -10,21 +10,26 @@ #include "base/time/time.h" #include "third_party/webrtc/api/scoped_refptr.h" -namespace content { +namespace blink { + +std::unique_ptr<WebRTCRtpSource> CreateRTCRtpSource( + const webrtc::RtpSource& source) { + return std::make_unique<RTCRtpSource>(source); +} RTCRtpSource::RTCRtpSource(const webrtc::RtpSource& source) : source_(source) {} RTCRtpSource::~RTCRtpSource() {} -blink::WebRTCRtpSource::Type RTCRtpSource::SourceType() const { +WebRTCRtpSource::Type RTCRtpSource::SourceType() const { switch (source_.source_type()) { case webrtc::RtpSourceType::SSRC: - return blink::WebRTCRtpSource::Type::kSSRC; + return WebRTCRtpSource::Type::kSSRC; case webrtc::RtpSourceType::CSRC: - return blink::WebRTCRtpSource::Type::kCSRC; + return WebRTCRtpSource::Type::kCSRC; default: NOTREACHED(); - return blink::WebRTCRtpSource::Type::kSSRC; + return WebRTCRtpSource::Type::kSSRC; } } @@ -54,4 +59,4 @@ return source_.rtp_timestamp(); } -} // namespace content +} // namespace blink
diff --git a/content/renderer/media/webrtc/rtc_rtp_source.h b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h similarity index 65% rename from content/renderer/media/webrtc/rtc_rtp_source.h rename to third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h index ecf3fd73..cd771ac 100644 --- a/content/renderer/media/webrtc/rtc_rtp_source.h +++ b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h
@@ -2,23 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_RTC_RTP_SOURCE_H_ -#define CONTENT_RENDERER_MEDIA_WEBRTC_RTC_RTP_SOURCE_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_RTP_SOURCE_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_RTP_SOURCE_H_ #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "content/common/content_export.h" #include "third_party/blink/public/platform/web_rtc_rtp_source.h" #include "third_party/webrtc/api/rtp_receiver_interface.h" -namespace content { +namespace blink { -class CONTENT_EXPORT RTCRtpSource : public blink::WebRTCRtpSource { +class RTCRtpSource : public WebRTCRtpSource { public: explicit RTCRtpSource(const webrtc::RtpSource& source); ~RTCRtpSource() override; - blink::WebRTCRtpSource::Type SourceType() const override; + WebRTCRtpSource::Type SourceType() const override; base::TimeTicks Timestamp() const override; uint32_t Source() const override; base::Optional<double> AudioLevel() const override; @@ -30,6 +29,6 @@ DISALLOW_COPY_AND_ASSIGN(RTCRtpSource); }; -} // namespace content +} // namespace blink -#endif // CONTENT_RENDERER_MEDIA_WEBRTC_RTC_RTP_SOURCE_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_RTP_SOURCE_H_
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index cc2b679..f5d78e6 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1025,12 +1025,6 @@ name: "MouseSubframeNoImplicitCapture", }, { - name: "MuteButton", - depends_on: ["PictureInPictureAPI"], - origin_trial_feature_name: "MuteButton", - status: "experimental", - }, - { // Enabled when blink::features::kNativeFileSystemAPI is enabled. name: "NativeFileSystem", },
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 8259a185..ffb0d5c 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2993,7 +2993,6 @@ crbug.com/831729 external/wpt/event-timing/crossiframe.html [ Timeout ] crbug.com/831729 external/wpt/event-timing/observer-manual.html [ Skip ] -crbug.com/987236 [ Linux ] external/wpt/event-timing/bufferbeforeonload.html [ Timeout ] # Working on getting the CSP tests going: crbug.com/694525 external/wpt/content-security-policy/connect-src/worker-from-guid.sub.html [ Skip ] @@ -6269,7 +6268,6 @@ crbug.com/972476 std-switch/switch-appearance-customization.html [ Failure ] # Sheriff 2019-05-20 -crbug.com/963739 [ Fuchsia ] synthetic_gestures/smooth-scroll-tiny-delta.html [ Pass Timeout ] crbug.com/964239 external/wpt/css/css-scroll-snap/scroll-margin.html [ Pass Failure ] crbug.com/965389 [ Mac ] media/track/track-cue-rendering-position-auto.html [ Pass Failure ] crbug.com/965389 [ Mac ] virtual/audio-service/media/track/track-cue-rendering-position-auto.html [ Pass Failure ] @@ -6407,7 +6405,6 @@ # Sheriff 2019-07-26 crbug.com/835943 [ Debug ] http/tests/appcache/non-html.xhtml [ Crash Pass ] crbug.com/874866 [ Linux Debug ] media/controls/doubletap-to-jump-backwards.html [ Failure ] -crbug.com/988231 external/wpt/event-timing/observethenonload.html [ Pass Timeout ] crbug.com/988232 virtual/controls-refresh/fast/forms/controls-new-ui/password/password-alt-f8-twice.html [ Pass Failure ] crbug.com/988232 virtual/controls-refresh/fast/forms/controls-new-ui/password/password-alt-f8.html [ Pass Failure ] crbug.com/988232 virtual/controls-refresh/fast/forms/controls-new-ui/password/password-eye-icon-font-size-48px.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/WPTOverrideExpectations b/third_party/blink/web_tests/WPTOverrideExpectations index 0c79361..138e0849 100644 --- a/third_party/blink/web_tests/WPTOverrideExpectations +++ b/third_party/blink/web_tests/WPTOverrideExpectations
@@ -805,8 +805,6 @@ crbug.com/lpz external/wpt/event-timing/buffered-flag.html [ Timeout ] crbug.com/lpz external/wpt/event-timing/crossiframe.html [ Failure ] crbug.com/lpz external/wpt/event-timing/idlharness.any.html [ Failure ] -crbug.com/lpz external/wpt/event-timing/onloadthenobserve-firstInput.html [ Timeout ] -crbug.com/lpz external/wpt/event-timing/onloadthenobserve.html [ Timeout ] crbug.com/lpz external/wpt/event-timing/retrievability.html [ Timeout ] crbug.com/lpz external/wpt/event-timing/retrieve-firstInput.html [ Failure ] crbug.com/lpz external/wpt/event-timing/timingconditions.html [ Timeout ]
diff --git a/third_party/blink/web_tests/animations/interpolation/shape-image-threshold-interpolation.html b/third_party/blink/web_tests/animations/interpolation/shape-image-threshold-interpolation.html deleted file mode 100644 index 2f12343..0000000 --- a/third_party/blink/web_tests/animations/interpolation/shape-image-threshold-interpolation.html +++ /dev/null
@@ -1,79 +0,0 @@ -<!DOCTYPE html> -<meta charset="UTF-8"> -<style> -.parent { - shape-image-threshold: 0.4; -} -.target { - shape-image-threshold: 0.6; -} -</style> -<body> -<script src="resources/interpolation-test.js"></script> -<script> -assertInterpolation({ - property: 'shape-image-threshold', - from: neutralKeyframe, - to: '0.8', -}, [ - {at: -1.5, is: '0.3'}, - {at: -0.5, is: '0.5'}, - {at: 0, is: '0.6'}, - {at: 0.5, is: '0.7'}, - {at: 1, is: '0.8'}, - {at: 1.5, is: '0.9'}, -]); - -assertInterpolation({ - property: 'shape-image-threshold', - from: 'initial', - to: '0.8', -}, [ - {at: -1.5, is: '0'}, - {at: -0.5, is: '0'}, - {at: 0, is: '0'}, - {at: 0.5, is: '0.4'}, - {at: 1, is: '0.8'}, - {at: 1.5, is: '1'}, -]); - -assertInterpolation({ - property: 'shape-image-threshold', - from: 'inherit', - to: '0.8', -}, [ - {at: -1.5, is: '0'}, - {at: -0.5, is: '0.2'}, - {at: 0, is: '0.4'}, - {at: 0.5, is: '0.6'}, - {at: 1, is: '0.8'}, - {at: 1.5, is: '1'}, -]); - -assertInterpolation({ - property: 'shape-image-threshold', - from: 'unset', - to: '0.8', -}, [ - {at: -1.5, is: '0'}, - {at: -0.5, is: '0'}, - {at: 0, is: '0'}, - {at: 0.5, is: '0.4'}, - {at: 1, is: '0.8'}, - {at: 1.5, is: '1'}, -]); - -assertInterpolation({ - property: 'shape-image-threshold', - from: '0.5', - to: '1' -}, [ - {at: -1.5, is: '0'}, - {at: -0.5, is: '0.25'}, - {at: 0, is: '0.5'}, - {at: 0.5, is: '0.75'}, - {at: 1, is: '1'}, - {at: 1.5, is: '1'} -]); -</script> -</body>
diff --git a/third_party/blink/web_tests/animations/interpolation/shape-margin-interpolation.html b/third_party/blink/web_tests/animations/interpolation/shape-margin-interpolation.html deleted file mode 100644 index 6bf3562..0000000 --- a/third_party/blink/web_tests/animations/interpolation/shape-margin-interpolation.html +++ /dev/null
@@ -1,79 +0,0 @@ -<!DOCTYPE html> -<meta charset="UTF-8"> -<style> -.parent { - shape-margin: 30px; -} -.target { - shape-margin: 10px; -} -</style> -<body> -<script src="resources/interpolation-test.js"></script> -<script> -assertInterpolation({ - property: 'shape-margin', - from: neutralKeyframe, - to: '20px', -}, [ - {at: -0.3, is: '7px'}, - {at: 0, is: '10px'}, - {at: 0.3, is: '13px'}, - {at: 0.6, is: '16px'}, - {at: 1, is: '20px'}, - {at: 1.5, is: '25px'}, -]); - -assertInterpolation({ - property: 'shape-margin', - from: 'initial', - to: '20px', -}, [ - {at: -0.3, is: '0px'}, - {at: 0, is: '0px'}, - {at: 0.3, is: '6px'}, - {at: 0.6, is: '12px'}, - {at: 1, is: '20px'}, - {at: 1.5, is: '30px'}, -]); - -assertInterpolation({ - property: 'shape-margin', - from: 'inherit', - to: '20px', -}, [ - {at: -0.3, is: '33px'}, - {at: 0, is: '30px'}, - {at: 0.3, is: '27px'}, - {at: 0.6, is: '24px'}, - {at: 1, is: '20px'}, - {at: 1.5, is: '15px'}, -]); - -assertInterpolation({ - property: 'shape-margin', - from: 'unset', - to: '20px', -}, [ - {at: -0.3, is: '0px'}, - {at: 0, is: '0px'}, - {at: 0.3, is: '6px'}, - {at: 0.6, is: '12px'}, - {at: 1, is: '20px'}, - {at: 1.5, is: '30px'}, -]); - -assertInterpolation({ - property: 'shape-margin', - from: '0px', - to: '100px' -}, [ - {at: -0.3, is: '0px'}, // CSS shape-margin can't be negative. - {at: 0, is: '0px'}, - {at: 0.3, is: '30px'}, - {at: 0.6, is: '60px'}, - {at: 1, is: '100px'}, - {at: 1.5, is: '150px'}, -]); -</script> -</body>
diff --git a/third_party/blink/web_tests/animations/interpolation/shape-outside-interpolation.html b/third_party/blink/web_tests/animations/interpolation/shape-outside-interpolation.html deleted file mode 100644 index 1e28397..0000000 --- a/third_party/blink/web_tests/animations/interpolation/shape-outside-interpolation.html +++ /dev/null
@@ -1,129 +0,0 @@ -<!DOCTYPE html> -<meta charset="UTF-8"> -<style> -.parent { - shape-outside: circle(80% at 30% 10%); -} -.target { - shape-outside: circle(60% at 10% 30%); -} -</style> -<body> -<script src="resources/interpolation-test.js"></script> -<script> -/* TODO: add inset test once blend() works for it */ - -assertInterpolation({ - property: 'shape-outside', - from: neutralKeyframe, - to: 'circle(40% at 20% 20%)', -}, [ - {at: -0.3, is: 'circle(66% at 7% 33%)'}, - {at: 0, is: 'circle(60% at 10% 30%)'}, - {at: 0.3, is: 'circle(54% at 13% 27%)'}, - {at: 0.6, is: 'circle(48% at 16% 24%)'}, - {at: 1, is: 'circle(40% at 20% 20%)'}, - {at: 1.5, is: 'circle(30% at 25% 15%)'}, -]); - -assertNoInterpolation({ - property: 'shape-outside', - from: 'initial', - to: 'circle(40% at 20% 20%)', -}); - -assertInterpolation({ - property: 'shape-outside', - from: 'inherit', - to: 'circle(40% at 20% 20%)', -}, [ - {at: -0.3, is: 'circle(92% at 33% 7%)'}, - {at: 0, is: 'circle(80% at 30% 10%)'}, - {at: 0.3, is: 'circle(68% at 27% 13%)'}, - {at: 0.6, is: 'circle(56% at 24% 16%)'}, - {at: 1, is: 'circle(40% at 20% 20%)'}, - {at: 1.5, is: 'circle(20% at 15% 25%)'}, -]); - -assertNoInterpolation({ - property: 'shape-outside', - from: 'unset', - to: 'circle(40% at 20% 20%)', -}); - -assertInterpolation({ - property: 'shape-outside', - from: 'circle(100% at 0% 0%)', - to: 'circle(50% at 25% 25%)', -}, [ - {at: -0.3, is: 'circle(115% at -7.5% -7.5%)'}, - {at: 0, is: 'circle(100% at 0% 0%)'}, - {at: 0.3, is: 'circle(85% at 7.5% 7.5%)'}, - {at: 0.6, is: 'circle(70% at 15% 15%)'}, - {at: 1, is: 'circle(50% at 25% 25%)'}, - {at: 1.5, is: 'circle(25% at 37.5% 37.5%)'} -]); - -assertInterpolation({ - property: 'shape-outside', - from: 'ellipse(100% 100% at 0% 0%)', - to: 'ellipse(50% 50% at 25% 25%)', -}, [ - {at: -0.3, is: 'ellipse(115% 115% at -7.5% -7.5%)'}, - {at: 0, is: 'ellipse(100% 100% at 0% 0%)'}, - {at: 0.3, is: 'ellipse(85% 85% at 7.5% 7.5%)'}, - {at: 0.6, is: 'ellipse(70% 70% at 15% 15%)'}, - {at: 1, is: 'ellipse(50% 50% at 25% 25%)'}, - {at: 1.5, is: 'ellipse(25% 25% at 37.5% 37.5%)'} -]); - -assertInterpolation({ - property: 'shape-outside', - from: 'polygon(nonzero, 0px 0px, 25px 25px, 50px 50px)', - to: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)', -}, [ - {at: -0.3, is: 'polygon(nonzero, -7.5px -7.5px, 17.5px 17.5px, 42.5px 42.5px)'}, - {at: 0, is: 'polygon(nonzero, 0px 0px, 25px 25px, 50px 50px)'}, - {at: 0.3, is: 'polygon(nonzero, 7.5px 7.5px, 32.5px 32.5px, 57.5px 57.5px)'}, - {at: 0.6, is: 'polygon(nonzero, 15px 15px, 40px 40px, 65px 65px)'}, - {at: 1, is: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)'}, - {at: 1.5, is: 'polygon(nonzero, 37.5px 37.5px, 62.5px 62.5px, 87.5px 87.5px)'} -]); - -assertNoInterpolation({ - property: 'shape-outside', - from: 'polygon(evenodd, 0px 0px, 25px 25px, 50px 50px)', - to: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)', -}); - -assertInterpolation({ - property: 'shape-outside', - from: 'inset(100%)', - to: 'inset(120%)', -}, [ - {at: -0.3, is: 'inset(94%)'}, - {at: 0, is: 'inset(100%)'}, - {at: 0.3, is: 'inset(106%)'}, - {at: 0.6, is: 'inset(112%)'}, - {at: 1, is: 'inset(120%)'}, - {at: 1.5, is: 'inset(130%)'}, -]); - -assertNoInterpolation({ - property: 'shape-outside', - from: 'none', - to: 'ellipse(100% 100% at 0% 0%)', -}); - -// TODO: add intermediate keyframe tests when CSS shapes position computed values are cleaned up -assertInterpolation({ - property: 'shape-outside', - from: 'circle(25% at right 5% bottom 15px)', - to: 'circle(45% at right 25% bottom 35px)', -}, [ - {at: 0.25, is: 'circle(30% at 90% calc(-20px + 100%))'}, - {at: 0.5, is: 'circle(35% at 85% calc(-25px + 100%))'}, - {at: 0.75, is: 'circle(40% at 80% calc(-30px + 100%))'}, -]); -</script> -</body>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json index ca78f1b9..d3fb62d 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -50291,6 +50291,30 @@ {} ] ], + "css/css-grid/grid-items/grid-item-rel-pos-001.html": [ + [ + "css/css-grid/grid-items/grid-item-rel-pos-001.html", + [ + [ + "/css/css-grid/grid-items/grid-item-rel-pos-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-grid/grid-items/grid-item-rel-pos-002.html": [ + [ + "css/css-grid/grid-items/grid-item-rel-pos-002.html", + [ + [ + "/css/css-grid/grid-items/grid-item-rel-pos-002-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-grid/grid-items/grid-items-001.html": [ [ "css/css-grid/grid-items/grid-items-001.html", @@ -140142,6 +140166,12 @@ "css/css-grid/grid-items/grid-item-percentage-sizes-003-ref.html": [ [] ], + "css/css-grid/grid-items/grid-item-rel-pos-001-ref.html": [ + [] + ], + "css/css-grid/grid-items/grid-item-rel-pos-002-ref.html": [ + [] + ], "css/css-grid/grid-items/grid-items-sizing-alignment-001-ref.html": [ [] ], @@ -152391,6 +152421,9 @@ "dom/historical-expected.txt": [ [] ], + "dom/idlharness.window_exclude=Node-expected.txt": [ + [] + ], "dom/interfaces-expected.txt": [ [] ], @@ -154608,12 +154641,6 @@ "fetch/api/basic/request-upload.any.worker-expected.txt": [ [] ], - "fetch/api/basic/scheme-data.any-expected.txt": [ - [] - ], - "fetch/api/basic/scheme-data.any.worker-expected.txt": [ - [] - ], "fetch/api/cors/cors-filtering-worker-expected.txt": [ [] ], @@ -222581,24 +222608,150 @@ {} ] ], - "dom/interface-objects.html": [ + "dom/idlharness.any.js": [ [ - "dom/interface-objects.html", - {} - ] - ], - "dom/interfaces.html": [ - [ - "dom/interfaces.html?exclude=Node", + "dom/idlharness.any.serviceworker.html", { + "script_metadata": [ + [ + "global", + "!window,worker" + ], + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" + ], + [ + "timeout", + "long" + ] + ], "timeout": "long" } ], [ - "dom/interfaces.html?include=Node", + "dom/idlharness.any.sharedworker.html", { + "script_metadata": [ + [ + "global", + "!window,worker" + ], + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" + ], + [ + "timeout", + "long" + ] + ], "timeout": "long" } + ], + [ + "dom/idlharness.any.worker.html", + { + "script_metadata": [ + [ + "global", + "!window,worker" + ], + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "dom/idlharness.window.js": [ + [ + "dom/idlharness.window.html?exclude=Node", + { + "script_metadata": [ + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "variant", + "?include=Node" + ], + [ + "variant", + "?exclude=Node" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "dom/idlharness.window.html?include=Node", + { + "script_metadata": [ + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" + ], + [ + "script", + "/common/subset-tests-by-key.js" + ], + [ + "variant", + "?include=Node" + ], + [ + "variant", + "?exclude=Node" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], + "dom/interface-objects.html": [ + [ + "dom/interface-objects.html", + {} ] ], "dom/lists/DOMTokenList-Iterable.html": [ @@ -294341,12 +294494,26 @@ {} ] ], + "trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html": [ + [ + "trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html", + {} + ] + ], "trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html": [ [ "trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html", {} ] ], + "trusted-types/TrustedTypePolicyFactory-metadata.tentative.html": [ + [ + "trusted-types/TrustedTypePolicyFactory-metadata.tentative.html", + { + "timeout": "long" + } + ] + ], "trusted-types/Window-TrustedTypes.tentative.html": [ [ "trusted-types/Window-TrustedTypes.tentative.html", @@ -327306,7 +327473,7 @@ "support" ], "audio-output/idlharness.https.window.js": [ - "f10e523bcdc530ee1dbd04a52541ac0b343e9376", + "c13b167296d8059b96bfa4704714051e341ee987", "testharness" ], "audio-output/setSinkId-manual.https.html": [ @@ -327610,7 +327777,7 @@ "support" ], "beacon/idlharness.any.js": [ - "958daf4865d1d7c9dfb621a163e15a8862330d2b", + "bf267ab8bdce52ce32df4ea3a53b30b6d35c8000", "testharness" ], "beacon/resources/beacon.py": [ @@ -370777,6 +370944,22 @@ "fccf4fe0a6ed1f128ff7ec2b322a4a2916c873b1", "reftest" ], + "css/css-grid/grid-items/grid-item-rel-pos-001-ref.html": [ + "a6305e560ef9ae01b5f89df59f3d42cd9ce4ab85", + "support" + ], + "css/css-grid/grid-items/grid-item-rel-pos-001.html": [ + "d72df4126ddc096036a84199616a35fd49c4cc36", + "reftest" + ], + "css/css-grid/grid-items/grid-item-rel-pos-002-ref.html": [ + "643b80e1ca88d4bf332c02637b1fe0478e951f1e", + "support" + ], + "css/css-grid/grid-items/grid-item-rel-pos-002.html": [ + "4a4d6c843ac4f82cb1403a15739174ec781634ef", + "reftest" + ], "css/css-grid/grid-items/grid-items-001.html": [ "fc9b27be4d1eb62d13afc9da04790da748b1a6ba", "reftest" @@ -420325,6 +420508,18 @@ "921fa07b3f6de0f9a579b75b14d6509039765205", "testharness" ], + "dom/idlharness.any.js": [ + "db841dc75b73d0cd22d9f273cd9277ce99c2843d", + "testharness" + ], + "dom/idlharness.window.js": [ + "3f44ed5adbe4320e6399cc300343743924f626e3", + "testharness" + ], + "dom/idlharness.window_exclude=Node-expected.txt": [ + "217c77d9778dbd9ac1cf39d3bfd1fe7b4b02f807", + "support" + ], "dom/interface-objects.html": [ "936d63517eada5521f814fabdbd785a57b9640b2", "testharness" @@ -420333,10 +420528,6 @@ "648f8f6475fb0fc829bdaaf49e379333b7d5489f", "support" ], - "dom/interfaces.html": [ - "111608bcaec1c39fa832474ebe014e8730a40c4e", - "testharness" - ], "dom/interfaces_exclude=Node-expected.txt": [ "e5d121860dcb77cc0fc0f8cb9c18ffbc5edc8986", "support" @@ -424674,7 +424865,7 @@ "testharness" ], "encrypted-media/idlharness.https.html": [ - "6a2ae80a5384aa885d7a1545b19f41cc828c420e", + "805094280771a2b0828a517c24bc4abf1b77d076", "testharness" ], "encrypted-media/polyfill/cast-polyfill.js": [ @@ -426553,18 +426744,10 @@ "fb1357eaf294b8973f44af30c2fafc40100d8eaf", "testharness" ], - "fetch/api/basic/scheme-data.any-expected.txt": [ - "012001f6e498a62417525e92ddc0d0698114d020", - "support" - ], "fetch/api/basic/scheme-data.any.js": [ "2ff2545cc6463f855d6f8ad1657407c85343a7e7", "testharness" ], - "fetch/api/basic/scheme-data.any.worker-expected.txt": [ - "012001f6e498a62417525e92ddc0d0698114d020", - "support" - ], "fetch/api/basic/scheme-others.sub.any.js": [ "5f9848ff4c297d662a82aa9e847f548371c33d19", "testharness" @@ -429294,7 +429477,7 @@ "testharness" ], "geolocation-API/idlharness.window.js": [ - "f8c92c121352b6daffe3c3b289f49d3572292c10", + "fe4ac8895dfb6e889eded7d694e3c87905868b4f", "testharness" ], "geolocation-API/support.js": [ @@ -454142,7 +454325,7 @@ "manual" ], "mediacapture-depth/idlharness.html": [ - "1afc6e5a05b2b8e0a288e7b680cf2920bdd1c525", + "963229aaca31dd8b92a07e1bb1da4c3eace7ad5b", "testharness" ], "mediacapture-fromelement/META.yml": [ @@ -454518,7 +454701,7 @@ "testharness" ], "mediacapture-streams/idlharness.https.window.js": [ - "5b255fca6b0b770ab6f849afe5d657c66052215a", + "594e1121b005ea3cd7ef1f30aa15fbed07dff1a4", "testharness" ], "mediacapture-streams/idlharness.window-expected.txt": [ @@ -464246,7 +464429,7 @@ "manual" ], "orientation-event/idlharness.https.window.js": [ - "ed8309d6480eaaec45e986a3391854d67b01ba2d", + "55cfed9276b480d7f70c616fa8d815f6ec925d66", "testharness" ], "orientation-event/ondeviceorientationabsolute.https.html": [ @@ -465326,7 +465509,7 @@ "support" ], "permissions/interfaces.any.js": [ - "b93453886930679c557a5c4a01651150b82670d9", + "ff0a969badace39c3c4466c4528e30c21355e132", "testharness" ], "permissions/test-background-fetch-permission.html": [ @@ -475726,7 +475909,7 @@ "testharness" ], "requestidlecallback/idlharness.window.js": [ - "2c9f6593208a4070d590fd81854ee78c5d20ce4d", + "69cd5a49b0432a65db9da267248a6f97d93cd0b9", "testharness" ], "requestidlecallback/resources/post_name_on_load.html": [ @@ -477102,7 +477285,7 @@ "testharness" ], "server-timing/idlharness.https.any.js": [ - "9c101e0f4cf2c5ef0196ac18342c8329755f794e", + "ded320f0f61f4de1132d5cfb76a7e74a16154f3c", "testharness" ], "server-timing/navigation_timing_idl.https.html": [ @@ -490562,7 +490745,7 @@ "testharness" ], "trusted-types/GlobalEventHandlers-onclick.tentative.html": [ - "6e8c560ebd1dafb4cc2b4509b2340790dade49c2", + "8c9c2f1a70bdb368bf535f40b8eae136c2eee23a", "testharness" ], "trusted-types/HTMLElement-generic.tentative.html": [ @@ -490645,10 +490828,18 @@ "ea00566854d12cbd6d2610aafdac44fd549ffbe7", "testharness" ], + "trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html": [ + "90fc7d5566d8d74dd70b7ff74a349dc424b4cdf8", + "testharness" + ], "trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html": [ "854f69ed1e550bd660b8cf7a18b4a81a666072fd", "testharness" ], + "trusted-types/TrustedTypePolicyFactory-metadata.tentative.html": [ + "694e4d2660fce5c3b89e457023ea147c84d67834", + "testharness" + ], "trusted-types/Window-TrustedTypes.tentative.html": [ "5bbb4356c21d249a21c8204aad6c9ba7a353cb4e", "testharness" @@ -504242,7 +504433,7 @@ "testharness" ], "xhr/data-uri-expected.txt": [ - "bf77d17f26baf3ae886b4021f34a3a882cc9f663", + "c0d444f8132ff4f4691880be13c562e5e42b355b", "support" ], "xhr/data-uri.htm": [
diff --git a/third_party/blink/web_tests/external/wpt/audio-output/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/audio-output/idlharness.https.window.js index f10e523b..c13b167 100644 --- a/third_party/blink/web_tests/external/wpt/audio-output/idlharness.https.window.js +++ b/third_party/blink/web_tests/external/wpt/audio-output/idlharness.https.window.js
@@ -5,20 +5,15 @@ 'use strict'; -promise_test(async () => { - const srcs = ['audio-output', 'dom', 'html']; - const [idl, dom, html] = await Promise.all( - srcs.map(i => fetch(`/interfaces/${i}.idl`).then(r => r.text()))); - - const idl_array = new IdlArray(); - idl_array.add_idls(idl); - idl_array.add_dependency_idls(html); - idl_array.add_dependency_idls(dom); - self.audio = document.createElement('audio'); - self.video = document.createElement('video'); - idl_array.add_objects({ - HTMLAudioElement: ['audio'], - HTMLVideoElement: ['video'] - }); - idl_array.test(); -}, 'Test IDL implementation of audio-output API'); +idl_test( + ['audio-output'], + ['html', 'dom'], + idl_array => { + self.audio = document.createElement('audio'); + self.video = document.createElement('video'); + idl_array.add_objects({ + HTMLAudioElement: ['audio'], + HTMLVideoElement: ['video'] + }); + } +);
diff --git a/third_party/blink/web_tests/external/wpt/beacon/idlharness.any.js b/third_party/blink/web_tests/external/wpt/beacon/idlharness.any.js index 958daf4..bf267ab 100644 --- a/third_party/blink/web_tests/external/wpt/beacon/idlharness.any.js +++ b/third_party/blink/web_tests/external/wpt/beacon/idlharness.any.js
@@ -3,15 +3,12 @@ // https://w3c.github.io/beacon/ -promise_test(async () => { - const idl = await fetch('/interfaces/beacon.idl').then(r => r.text()); - const html = await fetch('/interfaces/html.idl').then(r => r.text()); - - const idl_array = new IdlArray(); - idl_array.add_idls(idl); - idl_array.add_dependency_idls(html); - idl_array.add_objects({ - Navigator: ['navigator'], - }); - idl_array.test(); -}, 'beacon interfaces'); +idl_test( + ['beacon'], + ['html'], + idl_array => { + idl_array.add_objects({ + Navigator: ['navigator'], + }); + } +);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001-ref.html new file mode 100644 index 0000000..a6305e56 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001-ref.html
@@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<meta charset="utf-8"> +<title>Reference: Rel.pos. grid item with style change.</title> +<link rel="author" title="James0x57" href="mailto:James0x57@gmail.com"> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +.grid { + margin: 40px; + display: grid; + grid: auto / repeat(3,100px); + grid-gap: 20px; +} +span, even { + position: relative; + min-height: 20px; + background: grey; + left: 0px; +} +.offset even { + left: 50%; +} + +</style> + + +<div class="grid offset"> + <span></span><span></span><span></span> + <even></even><even></even><even></even> + <span></span><span></span><span></span> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001.html new file mode 100644 index 0000000..d72df41 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001.html
@@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<meta charset="utf-8"> +<title>CSS Grid Layout Test: Rel.pos. grid item with style change.</title> +<link rel="author" title="James0x57" href="mailto:James0x57@gmail.com"> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="help" href="http://www.w3.org/TR/css-grid-1/#grid-items" title="Grid Items"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1576355"> +<link rel="match" href="grid-item-rel-pos-001-ref.html"> +<meta name="assert" content="Checks that the rel.pos. grid items are positioned correctly after a 'left' style change."> +<style> +.grid { + margin: 40px; + display: grid; + grid: auto / repeat(3,100px); + grid-gap: 20px; +} +span, even { + position: relative; + min-height: 20px; + background: grey; + left: 0px; +} +.offset even { + left: 50%; +} + +</style> + + +<div class="grid offset"> + <span></span><span></span><span></span> + <even></even><even></even><even></even> + <span></span><span></span><span></span> +</div> + +<script> + document.body.offsetHeight; + let grid = document.querySelector('.grid'); + grid.classList.remove('offset') + document.body.offsetHeight; + grid.classList.add('offset') +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002-ref.html new file mode 100644 index 0000000..643b80e1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002-ref.html
@@ -0,0 +1,31 @@ +<!DOCTYPE HTML> +<meta charset="utf-8"> +<title>Reference: Rel.pos. centered grid item with style change.</title> +<link rel="author" title="James0x57" href="mailto:James0x57@gmail.com"> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +.grid { + margin: 40px; + display: grid; + grid: auto / repeat(3,100px); + grid-gap: 20px; +} +span, even { + position: relative; + min-height: 20px; + background: grey; + left: 0px; + width: 30px; + justify-self: center; +} +.offset even { + left: 20%; +} + +</style> + +<div class="grid offset"> + <span></span><span></span><span></span> + <even></even><even></even><even></even> + <span></span><span></span><span></span> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002.html new file mode 100644 index 0000000..4a4d6c8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002.html
@@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<meta charset="utf-8"> +<title>CSS Grid Layout Test: Rel.pos. centered grid item with style change.</title> +<link rel="author" title="James0x57" href="mailto:James0x57@gmail.com"> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="help" href="http://www.w3.org/TR/css-grid-1/#grid-items" title="Grid Items"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1576355"> +<link rel="match" href="grid-item-rel-pos-002-ref.html"> +<meta name="assert" content="Checks that the rel.pos. grid items are positioned correctly after a 'left' style change."> +<style> +.grid { + margin: 40px; + display: grid; + grid: auto / repeat(3,100px); + grid-gap: 20px; +} +span, even { + position: relative; + min-height: 20px; + background: grey; + left: 0px; + width: 30px; + justify-self: center; +} +.offset even { + left: 20%; +} + +</style> + +<div class="grid offset"> + <span></span><span></span><span></span> + <even></even><even></even><even></even> + <span></span><span></span><span></span> +</div> + +<script> + document.body.offsetHeight; + let grid = document.querySelector('.grid'); + grid.classList.remove('offset') + document.body.offsetHeight; + grid.classList.add('offset') +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-image-threshold-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-image-threshold-interpolation.html new file mode 100644 index 0000000..edac744 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-image-threshold-interpolation.html
@@ -0,0 +1,87 @@ +<!DOCTYPE html> +<meta charset="UTF-8"> +<title>shape-image-threshold interpolation</title> +<link rel="help" href="https://drafts.csswg.org/css-shapes/#shape-image-threshold-property"> +<meta name="assert" content="shape-image-threshold supports animation by computed value"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/interpolation-testcommon.js"></script> + +<style> +.parent { + shape-image-threshold: 0.4; +} +.target { + shape-image-threshold: 0.6; +} +</style> + +<body></body> + +<script> +test_interpolation({ + property: 'shape-image-threshold', + from: neutralKeyframe, + to: '0.8', +}, [ + {at: -1.5, expect: '0.3'}, + {at: -0.5, expect: '0.5'}, + {at: 0, expect: '0.6'}, + {at: 0.5, expect: '0.7'}, + {at: 1, expect: '0.8'}, + {at: 1.5, expect: '0.9'}, +]); + +test_interpolation({ + property: 'shape-image-threshold', + from: 'initial', + to: '0.8', +}, [ + {at: -1.5, expect: '0'}, + {at: -0.5, expect: '0'}, + {at: 0, expect: '0'}, + {at: 0.5, expect: '0.4'}, + {at: 1, expect: '0.8'}, + {at: 1.5, expect: '1'}, +]); + +test_interpolation({ + property: 'shape-image-threshold', + from: 'inherit', + to: '0.8', +}, [ + {at: -1.5, expect: '0'}, + {at: -0.5, expect: '0.2'}, + {at: 0, expect: '0.4'}, + {at: 0.5, expect: '0.6'}, + {at: 1, expect: '0.8'}, + {at: 1.5, expect: '1'}, +]); + +test_interpolation({ + property: 'shape-image-threshold', + from: 'unset', + to: '0.8', +}, [ + {at: -1.5, expect: '0'}, + {at: -0.5, expect: '0'}, + {at: 0, expect: '0'}, + {at: 0.5, expect: '0.4'}, + {at: 1, expect: '0.8'}, + {at: 1.5, expect: '1'}, +]); + +test_interpolation({ + property: 'shape-image-threshold', + from: '0.5', + to: '1' +}, [ + {at: -1.5, expect: '0'}, + {at: -0.5, expect: '0.25'}, + {at: 0, expect: '0.5'}, + {at: 0.5, expect: '0.75'}, + {at: 1, expect: '1'}, + {at: 1.5, expect: '1'} +]); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-margin-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-margin-interpolation.html new file mode 100644 index 0000000..48b3d0c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-margin-interpolation.html
@@ -0,0 +1,87 @@ +<!DOCTYPE html> +<meta charset="UTF-8"> +<title>shape-margin interpolation</title> +<link rel="help" href="https://drafts.csswg.org/css-shapes/#shape-margin-property"> +<meta name="assert" content="shape-margin supports animation by computed value"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/interpolation-testcommon.js"></script> + +<style> +.parent { + shape-margin: 30px; +} +.target { + shape-margin: 10px; +} +</style> + +<body></body> + +<script> +test_interpolation({ + property: 'shape-margin', + from: neutralKeyframe, + to: '20px', +}, [ + {at: -0.3, expect: '7px'}, + {at: 0, expect: '10px'}, + {at: 0.3, expect: '13px'}, + {at: 0.6, expect: '16px'}, + {at: 1, expect: '20px'}, + {at: 1.5, expect: '25px'}, +]); + +test_interpolation({ + property: 'shape-margin', + from: 'initial', + to: '20px', +}, [ + {at: -0.3, expect: '0px'}, + {at: 0, expect: '0px'}, + {at: 0.3, expect: '6px'}, + {at: 0.6, expect: '12px'}, + {at: 1, expect: '20px'}, + {at: 1.5, expect: '30px'}, +]); + +test_interpolation({ + property: 'shape-margin', + from: 'inherit', + to: '20px', +}, [ + {at: -0.3, expect: '33px'}, + {at: 0, expect: '30px'}, + {at: 0.3, expect: '27px'}, + {at: 0.6, expect: '24px'}, + {at: 1, expect: '20px'}, + {at: 1.5, expect: '15px'}, +]); + +test_interpolation({ + property: 'shape-margin', + from: 'unset', + to: '20px', +}, [ + {at: -0.3, expect: '0px'}, + {at: 0, expect: '0px'}, + {at: 0.3, expect: '6px'}, + {at: 0.6, expect: '12px'}, + {at: 1, expect: '20px'}, + {at: 1.5, expect: '30px'}, +]); + +test_interpolation({ + property: 'shape-margin', + from: '0px', + to: '100px' +}, [ + {at: -0.3, expect: '0px'}, // CSS shape-margin can't be negative. + {at: 0, expect: '0px'}, + {at: 0.3, expect: '30px'}, + {at: 0.6, expect: '60px'}, + {at: 1, expect: '100px'}, + {at: 1.5, expect: '150px'}, +]); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-outside-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-outside-interpolation.html new file mode 100644 index 0000000..3380acd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-outside-interpolation.html
@@ -0,0 +1,137 @@ +<!DOCTYPE html> +<meta charset="UTF-8"> +<title>shape-outside interpolation</title> +<link rel="help" href="https://drafts.csswg.org/css-shapes/#shape-outside-property"> +<meta name="assert" content="shape-outside supports animation as <basic-shape> or discrete"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/interpolation-testcommon.js"></script> + +<style> +.parent { + shape-outside: circle(80% at 30% 10%); +} +.target { + shape-outside: circle(60% at 10% 30%); +} +</style> + +<body></body> + +<script> +/* TODO: add inset test once blend() works for it */ + +test_interpolation({ + property: 'shape-outside', + from: neutralKeyframe, + to: 'circle(40% at 20% 20%)', +}, [ + {at: -0.3, expect: 'circle(66% at 7% 33%)'}, + {at: 0, expect: 'circle(60% at 10% 30%)'}, + {at: 0.3, expect: 'circle(54% at 13% 27%)'}, + {at: 0.6, expect: 'circle(48% at 16% 24%)'}, + {at: 1, expect: 'circle(40% at 20% 20%)'}, + {at: 1.5, expect: 'circle(30% at 25% 15%)'}, +]); + +test_no_interpolation({ + property: 'shape-outside', + from: 'initial', + to: 'circle(40% at 20% 20%)', +}); + +test_interpolation({ + property: 'shape-outside', + from: 'inherit', + to: 'circle(40% at 20% 20%)', +}, [ + {at: -0.3, expect: 'circle(92% at 33% 7%)'}, + {at: 0, expect: 'circle(80% at 30% 10%)'}, + {at: 0.3, expect: 'circle(68% at 27% 13%)'}, + {at: 0.6, expect: 'circle(56% at 24% 16%)'}, + {at: 1, expect: 'circle(40% at 20% 20%)'}, + {at: 1.5, expect: 'circle(20% at 15% 25%)'}, +]); + +test_no_interpolation({ + property: 'shape-outside', + from: 'unset', + to: 'circle(40% at 20% 20%)', +}); + +test_interpolation({ + property: 'shape-outside', + from: 'circle(100% at 0% 0%)', + to: 'circle(50% at 25% 25%)', +}, [ + {at: -0.3, expect: 'circle(115% at -7.5% -7.5%)'}, + {at: 0, expect: 'circle(100% at 0% 0%)'}, + {at: 0.3, expect: 'circle(85% at 7.5% 7.5%)'}, + {at: 0.6, expect: 'circle(70% at 15% 15%)'}, + {at: 1, expect: 'circle(50% at 25% 25%)'}, + {at: 1.5, expect: 'circle(25% at 37.5% 37.5%)'} +]); + +test_interpolation({ + property: 'shape-outside', + from: 'ellipse(100% 100% at 0% 0%)', + to: 'ellipse(50% 50% at 25% 25%)', +}, [ + {at: -0.3, expect: 'ellipse(115% 115% at -7.5% -7.5%)'}, + {at: 0, expect: 'ellipse(100% 100% at 0% 0%)'}, + {at: 0.3, expect: 'ellipse(85% 85% at 7.5% 7.5%)'}, + {at: 0.6, expect: 'ellipse(70% 70% at 15% 15%)'}, + {at: 1, expect: 'ellipse(50% 50% at 25% 25%)'}, + {at: 1.5, expect: 'ellipse(25% 25% at 37.5% 37.5%)'} +]); + +test_interpolation({ + property: 'shape-outside', + from: 'polygon(nonzero, 0px 0px, 25px 25px, 50px 50px)', + to: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)', +}, [ + {at: -0.3, expect: 'polygon(nonzero, -7.5px -7.5px, 17.5px 17.5px, 42.5px 42.5px)'}, + {at: 0, expect: 'polygon(nonzero, 0px 0px, 25px 25px, 50px 50px)'}, + {at: 0.3, expect: 'polygon(nonzero, 7.5px 7.5px, 32.5px 32.5px, 57.5px 57.5px)'}, + {at: 0.6, expect: 'polygon(nonzero, 15px 15px, 40px 40px, 65px 65px)'}, + {at: 1, expect: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)'}, + {at: 1.5, expect: 'polygon(nonzero, 37.5px 37.5px, 62.5px 62.5px, 87.5px 87.5px)'} +]); + +test_no_interpolation({ + property: 'shape-outside', + from: 'polygon(evenodd, 0px 0px, 25px 25px, 50px 50px)', + to: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)', +}); + +test_interpolation({ + property: 'shape-outside', + from: 'inset(100%)', + to: 'inset(120%)', +}, [ + {at: -0.3, expect: 'inset(94%)'}, + {at: 0, expect: 'inset(100%)'}, + {at: 0.3, expect: 'inset(106%)'}, + {at: 0.6, expect: 'inset(112%)'}, + {at: 1, expect: 'inset(120%)'}, + {at: 1.5, expect: 'inset(130%)'}, +]); + +test_no_interpolation({ + property: 'shape-outside', + from: 'none', + to: 'ellipse(100% 100% at 0% 0%)', +}); + +// TODO: add intermediate keyframe tests when CSS shapes position computed values are cleaned up +test_interpolation({ + property: 'shape-outside', + from: 'circle(25% at right 5% bottom 15px)', + to: 'circle(45% at right 25% bottom 35px)', +}, [ + {at: 0.25, expect: 'circle(30% at 90% calc(-20px + 100%))'}, + {at: 0.5, expect: 'circle(35% at 85% calc(-25px + 100%))'}, + {at: 0.75, expect: 'circle(40% at 80% calc(-30px + 100%))'}, +]); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/idlharness.any.js b/third_party/blink/web_tests/external/wpt/dom/idlharness.any.js new file mode 100644 index 0000000..db841dc7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/idlharness.any.js
@@ -0,0 +1,22 @@ +// META: global=!window,worker +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js +// META: timeout=long + +'use strict'; + +idl_test( + ['dom'], + ['html'], + idl_array => { + idl_array.add_objects({ + EventTarget: ['new EventTarget()'], + Event: ['new Event("foo")'], + CustomEvent: ['new CustomEvent("foo")'], + AbortController: ['new AbortController()'], + AbortSignal: ['new AbortController().signal'], + }); + } +); + +done();
diff --git a/third_party/blink/web_tests/external/wpt/dom/idlharness.window.js b/third_party/blink/web_tests/external/wpt/dom/idlharness.window.js new file mode 100644 index 0000000..3f44ed5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/idlharness.window.js
@@ -0,0 +1,44 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js +// META: script=/common/subset-tests-by-key.js +// META: variant=?include=Node +// META: variant=?exclude=Node +// META: timeout=long + +'use strict'; + +idl_test( + ['dom'], + ['html'], + idl_array => { + self.xmlDoc = document.implementation.createDocument(null, '', null); + self.detachedRange = document.createRange(); + detachedRange.detach(); + self.element = xmlDoc.createElementNS(null, 'test'); + element.setAttribute('bar', 'baz'); + + idl_array.add_objects({ + EventTarget: ['new EventTarget()'], + Event: ['document.createEvent("Event")', 'new Event("foo")'], + CustomEvent: ['new CustomEvent("foo")'], + AbortController: ['new AbortController()'], + AbortSignal: ['new AbortController().signal'], + Document: ['new Document()'], + XMLDocument: ['xmlDoc'], + DOMImplementation: ['document.implementation'], + DocumentFragment: ['document.createDocumentFragment()'], + DocumentType: ['document.doctype'], + Element: ['element'], + Attr: ['document.querySelector("[id]").attributes[0]'], + Text: ['document.createTextNode("abc")'], + ProcessingInstruction: ['xmlDoc.createProcessingInstruction("abc", "def")'], + Comment: ['document.createComment("abc")'], + Range: ['document.createRange()', 'detachedRange'], + NodeIterator: ['document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false)'], + TreeWalker: ['document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false)'], + NodeList: ['document.querySelectorAll("script")'], + HTMLCollection: ['document.body.children'], + DOMTokenList: ['document.body.classList'], + }); + } +);
diff --git a/third_party/blink/web_tests/external/wpt/dom/idlharness.window_exclude=Node-expected.txt b/third_party/blink/web_tests/external/wpt/dom/idlharness.window_exclude=Node-expected.txt new file mode 100644 index 0000000..217c77d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/idlharness.window_exclude=Node-expected.txt
@@ -0,0 +1,1108 @@ +This is a testharness.js-based test. +Found 1104 tests; 1080 PASS, 24 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS idl_test setup +PASS Partial interface Window: original interface defined +PASS Event interface: existence and properties of interface object +PASS Event interface object length +PASS Event interface object name +PASS Event interface: existence and properties of interface prototype object +PASS Event interface: existence and properties of interface prototype object's "constructor" property +PASS Event interface: existence and properties of interface prototype object's @@unscopables property +PASS Event interface: attribute type +PASS Event interface: attribute target +PASS Event interface: attribute srcElement +PASS Event interface: attribute currentTarget +PASS Event interface: operation composedPath() +PASS Event interface: constant NONE on interface object +PASS Event interface: constant NONE on interface prototype object +PASS Event interface: constant CAPTURING_PHASE on interface object +PASS Event interface: constant CAPTURING_PHASE on interface prototype object +PASS Event interface: constant AT_TARGET on interface object +PASS Event interface: constant AT_TARGET on interface prototype object +PASS Event interface: constant BUBBLING_PHASE on interface object +PASS Event interface: constant BUBBLING_PHASE on interface prototype object +PASS Event interface: attribute eventPhase +PASS Event interface: operation stopPropagation() +PASS Event interface: attribute cancelBubble +PASS Event interface: operation stopImmediatePropagation() +PASS Event interface: attribute bubbles +PASS Event interface: attribute cancelable +PASS Event interface: attribute returnValue +PASS Event interface: operation preventDefault() +PASS Event interface: attribute defaultPrevented +PASS Event interface: attribute composed +PASS Event interface: attribute timeStamp +PASS Event interface: operation initEvent(DOMString, boolean, boolean) +PASS Event must be primary interface of document.createEvent("Event") +PASS Stringification of document.createEvent("Event") +PASS Event interface: document.createEvent("Event") must inherit property "type" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "target" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "srcElement" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "currentTarget" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "composedPath()" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "NONE" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "CAPTURING_PHASE" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "AT_TARGET" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "BUBBLING_PHASE" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "eventPhase" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "stopPropagation()" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "cancelBubble" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "stopImmediatePropagation()" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "bubbles" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "cancelable" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "returnValue" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "preventDefault()" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "defaultPrevented" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "composed" with the proper type +PASS Event interface: document.createEvent("Event") must have own property "isTrusted" +PASS Event interface: document.createEvent("Event") must inherit property "timeStamp" with the proper type +PASS Event interface: document.createEvent("Event") must inherit property "initEvent(DOMString, boolean, boolean)" with the proper type +PASS Event interface: calling initEvent(DOMString, boolean, boolean) on document.createEvent("Event") with too few arguments must throw TypeError +PASS Event must be primary interface of new Event("foo") +PASS Stringification of new Event("foo") +PASS Event interface: new Event("foo") must inherit property "type" with the proper type +PASS Event interface: new Event("foo") must inherit property "target" with the proper type +PASS Event interface: new Event("foo") must inherit property "srcElement" with the proper type +PASS Event interface: new Event("foo") must inherit property "currentTarget" with the proper type +PASS Event interface: new Event("foo") must inherit property "composedPath()" with the proper type +PASS Event interface: new Event("foo") must inherit property "NONE" with the proper type +PASS Event interface: new Event("foo") must inherit property "CAPTURING_PHASE" with the proper type +PASS Event interface: new Event("foo") must inherit property "AT_TARGET" with the proper type +PASS Event interface: new Event("foo") must inherit property "BUBBLING_PHASE" with the proper type +PASS Event interface: new Event("foo") must inherit property "eventPhase" with the proper type +PASS Event interface: new Event("foo") must inherit property "stopPropagation()" with the proper type +PASS Event interface: new Event("foo") must inherit property "cancelBubble" with the proper type +PASS Event interface: new Event("foo") must inherit property "stopImmediatePropagation()" with the proper type +PASS Event interface: new Event("foo") must inherit property "bubbles" with the proper type +PASS Event interface: new Event("foo") must inherit property "cancelable" with the proper type +PASS Event interface: new Event("foo") must inherit property "returnValue" with the proper type +PASS Event interface: new Event("foo") must inherit property "preventDefault()" with the proper type +PASS Event interface: new Event("foo") must inherit property "defaultPrevented" with the proper type +PASS Event interface: new Event("foo") must inherit property "composed" with the proper type +PASS Event interface: new Event("foo") must have own property "isTrusted" +PASS Event interface: new Event("foo") must inherit property "timeStamp" with the proper type +PASS Event interface: new Event("foo") must inherit property "initEvent(DOMString, boolean, boolean)" with the proper type +PASS Event interface: calling initEvent(DOMString, boolean, boolean) on new Event("foo") with too few arguments must throw TypeError +PASS CustomEvent interface: existence and properties of interface object +PASS CustomEvent interface object length +PASS CustomEvent interface object name +PASS CustomEvent interface: existence and properties of interface prototype object +PASS CustomEvent interface: existence and properties of interface prototype object's "constructor" property +PASS CustomEvent interface: existence and properties of interface prototype object's @@unscopables property +PASS CustomEvent interface: attribute detail +PASS CustomEvent interface: operation initCustomEvent(DOMString, boolean, boolean, any) +PASS CustomEvent must be primary interface of new CustomEvent("foo") +PASS Stringification of new CustomEvent("foo") +PASS CustomEvent interface: new CustomEvent("foo") must inherit property "detail" with the proper type +PASS CustomEvent interface: new CustomEvent("foo") must inherit property "initCustomEvent(DOMString, boolean, boolean, any)" with the proper type +PASS CustomEvent interface: calling initCustomEvent(DOMString, boolean, boolean, any) on new CustomEvent("foo") with too few arguments must throw TypeError +PASS Event interface: new CustomEvent("foo") must inherit property "type" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "target" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "srcElement" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "currentTarget" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "composedPath()" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "NONE" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "CAPTURING_PHASE" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "AT_TARGET" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "BUBBLING_PHASE" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "eventPhase" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "stopPropagation()" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "cancelBubble" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "stopImmediatePropagation()" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "bubbles" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "cancelable" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "returnValue" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "preventDefault()" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "defaultPrevented" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "composed" with the proper type +PASS Event interface: new CustomEvent("foo") must have own property "isTrusted" +PASS Event interface: new CustomEvent("foo") must inherit property "timeStamp" with the proper type +PASS Event interface: new CustomEvent("foo") must inherit property "initEvent(DOMString, boolean, boolean)" with the proper type +PASS Event interface: calling initEvent(DOMString, boolean, boolean) on new CustomEvent("foo") with too few arguments must throw TypeError +PASS EventTarget interface: existence and properties of interface object +PASS EventTarget interface object length +PASS EventTarget interface object name +PASS EventTarget interface: existence and properties of interface prototype object +PASS EventTarget interface: existence and properties of interface prototype object's "constructor" property +PASS EventTarget interface: existence and properties of interface prototype object's @@unscopables property +PASS EventTarget interface: operation addEventListener(DOMString, EventListener, [object Object],[object Object]) +PASS EventTarget interface: operation removeEventListener(DOMString, EventListener, [object Object],[object Object]) +PASS EventTarget interface: operation dispatchEvent(Event) +PASS EventTarget must be primary interface of new EventTarget() +PASS Stringification of new EventTarget() +PASS EventTarget interface: new EventTarget() must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on new EventTarget() with too few arguments must throw TypeError +PASS EventTarget interface: new EventTarget() must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on new EventTarget() with too few arguments must throw TypeError +PASS EventTarget interface: new EventTarget() must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on new EventTarget() with too few arguments must throw TypeError +PASS EventListener interface: existence and properties of interface object +PASS EventListener interface: existence and properties of interface prototype object +PASS EventListener interface: existence and properties of interface prototype object's "constructor" property +PASS EventListener interface: existence and properties of interface prototype object's @@unscopables property +PASS EventListener interface: operation handleEvent(Event) +PASS AbortController interface: existence and properties of interface object +PASS AbortController interface object length +PASS AbortController interface object name +PASS AbortController interface: existence and properties of interface prototype object +PASS AbortController interface: existence and properties of interface prototype object's "constructor" property +PASS AbortController interface: existence and properties of interface prototype object's @@unscopables property +PASS AbortController interface: attribute signal +PASS AbortController interface: operation abort() +PASS AbortController must be primary interface of new AbortController() +PASS Stringification of new AbortController() +PASS AbortController interface: new AbortController() must inherit property "signal" with the proper type +PASS AbortController interface: new AbortController() must inherit property "abort()" with the proper type +PASS AbortSignal interface: existence and properties of interface object +PASS AbortSignal interface object length +PASS AbortSignal interface object name +PASS AbortSignal interface: existence and properties of interface prototype object +PASS AbortSignal interface: existence and properties of interface prototype object's "constructor" property +PASS AbortSignal interface: existence and properties of interface prototype object's @@unscopables property +PASS AbortSignal interface: attribute aborted +PASS AbortSignal interface: attribute onabort +PASS AbortSignal must be primary interface of new AbortController().signal +PASS Stringification of new AbortController().signal +PASS AbortSignal interface: new AbortController().signal must inherit property "aborted" with the proper type +PASS AbortSignal interface: new AbortController().signal must inherit property "onabort" with the proper type +PASS EventTarget interface: new AbortController().signal must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on new AbortController().signal with too few arguments must throw TypeError +PASS EventTarget interface: new AbortController().signal must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on new AbortController().signal with too few arguments must throw TypeError +PASS EventTarget interface: new AbortController().signal must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on new AbortController().signal with too few arguments must throw TypeError +PASS NodeList interface: existence and properties of interface object +PASS NodeList interface object length +PASS NodeList interface object name +PASS NodeList interface: existence and properties of interface prototype object +PASS NodeList interface: existence and properties of interface prototype object's "constructor" property +PASS NodeList interface: existence and properties of interface prototype object's @@unscopables property +PASS NodeList interface: operation item(unsigned long) +PASS NodeList interface: attribute length +PASS NodeList interface: iterable<Node> +PASS NodeList must be primary interface of document.querySelectorAll("script") +PASS Stringification of document.querySelectorAll("script") +PASS NodeList interface: document.querySelectorAll("script") must inherit property "item(unsigned long)" with the proper type +PASS NodeList interface: calling item(unsigned long) on document.querySelectorAll("script") with too few arguments must throw TypeError +PASS NodeList interface: document.querySelectorAll("script") must inherit property "length" with the proper type +PASS HTMLCollection interface: existence and properties of interface object +PASS HTMLCollection interface object length +PASS HTMLCollection interface object name +PASS HTMLCollection interface: existence and properties of interface prototype object +PASS HTMLCollection interface: existence and properties of interface prototype object's "constructor" property +PASS HTMLCollection interface: existence and properties of interface prototype object's @@unscopables property +PASS HTMLCollection interface: attribute length +PASS HTMLCollection interface: operation item(unsigned long) +PASS HTMLCollection interface: operation namedItem(DOMString) +PASS HTMLCollection must be primary interface of document.body.children +PASS Stringification of document.body.children +PASS HTMLCollection interface: document.body.children must inherit property "length" with the proper type +PASS HTMLCollection interface: document.body.children must inherit property "item(unsigned long)" with the proper type +PASS HTMLCollection interface: calling item(unsigned long) on document.body.children with too few arguments must throw TypeError +PASS HTMLCollection interface: document.body.children must inherit property "namedItem(DOMString)" with the proper type +PASS HTMLCollection interface: calling namedItem(DOMString) on document.body.children with too few arguments must throw TypeError +PASS MutationObserver interface: existence and properties of interface object +PASS MutationObserver interface object length +PASS MutationObserver interface object name +PASS MutationObserver interface: existence and properties of interface prototype object +PASS MutationObserver interface: existence and properties of interface prototype object's "constructor" property +PASS MutationObserver interface: existence and properties of interface prototype object's @@unscopables property +PASS MutationObserver interface: operation observe(Node, MutationObserverInit) +PASS MutationObserver interface: operation disconnect() +PASS MutationObserver interface: operation takeRecords() +PASS MutationRecord interface: existence and properties of interface object +PASS MutationRecord interface object length +PASS MutationRecord interface object name +PASS MutationRecord interface: existence and properties of interface prototype object +PASS MutationRecord interface: existence and properties of interface prototype object's "constructor" property +PASS MutationRecord interface: existence and properties of interface prototype object's @@unscopables property +PASS MutationRecord interface: attribute type +PASS MutationRecord interface: attribute target +PASS MutationRecord interface: attribute addedNodes +PASS MutationRecord interface: attribute removedNodes +PASS MutationRecord interface: attribute previousSibling +PASS MutationRecord interface: attribute nextSibling +PASS MutationRecord interface: attribute attributeName +PASS MutationRecord interface: attribute attributeNamespace +PASS MutationRecord interface: attribute oldValue +PASS Document interface: existence and properties of interface object +PASS Document interface object length +PASS Document interface object name +PASS Document interface: existence and properties of interface prototype object +PASS Document interface: existence and properties of interface prototype object's "constructor" property +FAIL Document interface: existence and properties of interface prototype object's @@unscopables property assert_false: Document.prototype[Symbol.unscopables] should not be writable expected false got true +PASS Document interface: attribute implementation +PASS Document interface: attribute URL +PASS Document interface: attribute documentURI +FAIL Document interface: attribute origin assert_true: The prototype object must have a property "origin" expected true got false +PASS Document interface: attribute compatMode +PASS Document interface: attribute characterSet +PASS Document interface: attribute charset +PASS Document interface: attribute inputEncoding +PASS Document interface: attribute contentType +PASS Document interface: attribute doctype +PASS Document interface: attribute documentElement +PASS Document interface: operation getElementsByTagName(DOMString) +PASS Document interface: operation getElementsByTagNameNS(DOMString, DOMString) +PASS Document interface: operation getElementsByClassName(DOMString) +PASS Document interface: operation createElement(DOMString, [object Object],[object Object]) +PASS Document interface: operation createElementNS(DOMString, DOMString, [object Object],[object Object]) +PASS Document interface: operation createDocumentFragment() +PASS Document interface: operation createTextNode(DOMString) +PASS Document interface: operation createCDATASection(DOMString) +PASS Document interface: operation createComment(DOMString) +PASS Document interface: operation createProcessingInstruction(DOMString, DOMString) +PASS Document interface: operation importNode(Node, boolean) +PASS Document interface: operation adoptNode(Node) +PASS Document interface: operation createAttribute(DOMString) +PASS Document interface: operation createAttributeNS(DOMString, DOMString) +PASS Document interface: operation createEvent(DOMString) +PASS Document interface: operation createRange() +PASS Document interface: operation createNodeIterator(Node, unsigned long, NodeFilter) +PASS Document interface: operation createTreeWalker(Node, unsigned long, NodeFilter) +PASS Document interface: operation getElementById(DOMString) +PASS Document interface: attribute children +PASS Document interface: attribute firstElementChild +PASS Document interface: attribute lastElementChild +PASS Document interface: attribute childElementCount +PASS Document interface: operation prepend([object Object],[object Object]) +PASS Document interface: operation append([object Object],[object Object]) +PASS Document interface: operation querySelector(DOMString) +PASS Document interface: operation querySelectorAll(DOMString) +PASS Document must be primary interface of new Document() +PASS Stringification of new Document() +PASS Document interface: new Document() must inherit property "implementation" with the proper type +PASS Document interface: new Document() must inherit property "URL" with the proper type +PASS Document interface: new Document() must inherit property "documentURI" with the proper type +FAIL Document interface: new Document() must inherit property "origin" with the proper type assert_inherits: property "origin" not found in prototype chain +PASS Document interface: new Document() must inherit property "compatMode" with the proper type +PASS Document interface: new Document() must inherit property "characterSet" with the proper type +PASS Document interface: new Document() must inherit property "charset" with the proper type +PASS Document interface: new Document() must inherit property "inputEncoding" with the proper type +PASS Document interface: new Document() must inherit property "contentType" with the proper type +PASS Document interface: new Document() must inherit property "doctype" with the proper type +PASS Document interface: new Document() must inherit property "documentElement" with the proper type +PASS Document interface: new Document() must inherit property "getElementsByTagName(DOMString)" with the proper type +PASS Document interface: calling getElementsByTagName(DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "getElementsByTagNameNS(DOMString, DOMString)" with the proper type +PASS Document interface: calling getElementsByTagNameNS(DOMString, DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "getElementsByClassName(DOMString)" with the proper type +PASS Document interface: calling getElementsByClassName(DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createElement(DOMString, [object Object],[object Object])" with the proper type +PASS Document interface: calling createElement(DOMString, [object Object],[object Object]) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createElementNS(DOMString, DOMString, [object Object],[object Object])" with the proper type +PASS Document interface: calling createElementNS(DOMString, DOMString, [object Object],[object Object]) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createDocumentFragment()" with the proper type +PASS Document interface: new Document() must inherit property "createTextNode(DOMString)" with the proper type +PASS Document interface: calling createTextNode(DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createCDATASection(DOMString)" with the proper type +PASS Document interface: calling createCDATASection(DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createComment(DOMString)" with the proper type +PASS Document interface: calling createComment(DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createProcessingInstruction(DOMString, DOMString)" with the proper type +PASS Document interface: calling createProcessingInstruction(DOMString, DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "importNode(Node, boolean)" with the proper type +PASS Document interface: calling importNode(Node, boolean) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "adoptNode(Node)" with the proper type +PASS Document interface: calling adoptNode(Node) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createAttribute(DOMString)" with the proper type +PASS Document interface: calling createAttribute(DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createAttributeNS(DOMString, DOMString)" with the proper type +PASS Document interface: calling createAttributeNS(DOMString, DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createEvent(DOMString)" with the proper type +PASS Document interface: calling createEvent(DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createRange()" with the proper type +PASS Document interface: new Document() must inherit property "createNodeIterator(Node, unsigned long, NodeFilter)" with the proper type +PASS Document interface: calling createNodeIterator(Node, unsigned long, NodeFilter) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "createTreeWalker(Node, unsigned long, NodeFilter)" with the proper type +PASS Document interface: calling createTreeWalker(Node, unsigned long, NodeFilter) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "getElementById(DOMString)" with the proper type +PASS Document interface: calling getElementById(DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "children" with the proper type +PASS Document interface: new Document() must inherit property "firstElementChild" with the proper type +PASS Document interface: new Document() must inherit property "lastElementChild" with the proper type +PASS Document interface: new Document() must inherit property "childElementCount" with the proper type +PASS Document interface: new Document() must inherit property "prepend([object Object],[object Object])" with the proper type +PASS Document interface: calling prepend([object Object],[object Object]) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "append([object Object],[object Object])" with the proper type +PASS Document interface: calling append([object Object],[object Object]) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "querySelector(DOMString)" with the proper type +PASS Document interface: calling querySelector(DOMString) on new Document() with too few arguments must throw TypeError +PASS Document interface: new Document() must inherit property "querySelectorAll(DOMString)" with the proper type +PASS Document interface: calling querySelectorAll(DOMString) on new Document() with too few arguments must throw TypeError +PASS EventTarget interface: new Document() must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on new Document() with too few arguments must throw TypeError +PASS EventTarget interface: new Document() must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on new Document() with too few arguments must throw TypeError +PASS EventTarget interface: new Document() must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on new Document() with too few arguments must throw TypeError +PASS XMLDocument interface: existence and properties of interface object +PASS XMLDocument interface object length +PASS XMLDocument interface object name +PASS XMLDocument interface: existence and properties of interface prototype object +PASS XMLDocument interface: existence and properties of interface prototype object's "constructor" property +PASS XMLDocument interface: existence and properties of interface prototype object's @@unscopables property +PASS XMLDocument must be primary interface of xmlDoc +PASS Stringification of xmlDoc +PASS Document interface: xmlDoc must inherit property "implementation" with the proper type +PASS Document interface: xmlDoc must inherit property "URL" with the proper type +PASS Document interface: xmlDoc must inherit property "documentURI" with the proper type +FAIL Document interface: xmlDoc must inherit property "origin" with the proper type assert_inherits: property "origin" not found in prototype chain +PASS Document interface: xmlDoc must inherit property "compatMode" with the proper type +PASS Document interface: xmlDoc must inherit property "characterSet" with the proper type +PASS Document interface: xmlDoc must inherit property "charset" with the proper type +PASS Document interface: xmlDoc must inherit property "inputEncoding" with the proper type +PASS Document interface: xmlDoc must inherit property "contentType" with the proper type +PASS Document interface: xmlDoc must inherit property "doctype" with the proper type +PASS Document interface: xmlDoc must inherit property "documentElement" with the proper type +PASS Document interface: xmlDoc must inherit property "getElementsByTagName(DOMString)" with the proper type +PASS Document interface: calling getElementsByTagName(DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "getElementsByTagNameNS(DOMString, DOMString)" with the proper type +PASS Document interface: calling getElementsByTagNameNS(DOMString, DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "getElementsByClassName(DOMString)" with the proper type +PASS Document interface: calling getElementsByClassName(DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createElement(DOMString, [object Object],[object Object])" with the proper type +PASS Document interface: calling createElement(DOMString, [object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createElementNS(DOMString, DOMString, [object Object],[object Object])" with the proper type +PASS Document interface: calling createElementNS(DOMString, DOMString, [object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createDocumentFragment()" with the proper type +PASS Document interface: xmlDoc must inherit property "createTextNode(DOMString)" with the proper type +PASS Document interface: calling createTextNode(DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createCDATASection(DOMString)" with the proper type +PASS Document interface: calling createCDATASection(DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createComment(DOMString)" with the proper type +PASS Document interface: calling createComment(DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createProcessingInstruction(DOMString, DOMString)" with the proper type +PASS Document interface: calling createProcessingInstruction(DOMString, DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "importNode(Node, boolean)" with the proper type +PASS Document interface: calling importNode(Node, boolean) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "adoptNode(Node)" with the proper type +PASS Document interface: calling adoptNode(Node) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createAttribute(DOMString)" with the proper type +PASS Document interface: calling createAttribute(DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createAttributeNS(DOMString, DOMString)" with the proper type +PASS Document interface: calling createAttributeNS(DOMString, DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createEvent(DOMString)" with the proper type +PASS Document interface: calling createEvent(DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createRange()" with the proper type +PASS Document interface: xmlDoc must inherit property "createNodeIterator(Node, unsigned long, NodeFilter)" with the proper type +PASS Document interface: calling createNodeIterator(Node, unsigned long, NodeFilter) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "createTreeWalker(Node, unsigned long, NodeFilter)" with the proper type +PASS Document interface: calling createTreeWalker(Node, unsigned long, NodeFilter) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "getElementById(DOMString)" with the proper type +PASS Document interface: calling getElementById(DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "children" with the proper type +PASS Document interface: xmlDoc must inherit property "firstElementChild" with the proper type +PASS Document interface: xmlDoc must inherit property "lastElementChild" with the proper type +PASS Document interface: xmlDoc must inherit property "childElementCount" with the proper type +PASS Document interface: xmlDoc must inherit property "prepend([object Object],[object Object])" with the proper type +PASS Document interface: calling prepend([object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "append([object Object],[object Object])" with the proper type +PASS Document interface: calling append([object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "querySelector(DOMString)" with the proper type +PASS Document interface: calling querySelector(DOMString) on xmlDoc with too few arguments must throw TypeError +PASS Document interface: xmlDoc must inherit property "querySelectorAll(DOMString)" with the proper type +PASS Document interface: calling querySelectorAll(DOMString) on xmlDoc with too few arguments must throw TypeError +PASS EventTarget interface: xmlDoc must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError +PASS EventTarget interface: xmlDoc must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError +PASS EventTarget interface: xmlDoc must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on xmlDoc with too few arguments must throw TypeError +PASS DOMImplementation interface: existence and properties of interface object +PASS DOMImplementation interface object length +PASS DOMImplementation interface object name +PASS DOMImplementation interface: existence and properties of interface prototype object +PASS DOMImplementation interface: existence and properties of interface prototype object's "constructor" property +PASS DOMImplementation interface: existence and properties of interface prototype object's @@unscopables property +PASS DOMImplementation interface: operation createDocumentType(DOMString, DOMString, DOMString) +PASS DOMImplementation interface: operation createDocument(DOMString, DOMString, DocumentType) +PASS DOMImplementation interface: operation createHTMLDocument(DOMString) +PASS DOMImplementation interface: operation hasFeature() +PASS DOMImplementation must be primary interface of document.implementation +PASS Stringification of document.implementation +PASS DOMImplementation interface: document.implementation must inherit property "createDocumentType(DOMString, DOMString, DOMString)" with the proper type +PASS DOMImplementation interface: calling createDocumentType(DOMString, DOMString, DOMString) on document.implementation with too few arguments must throw TypeError +PASS DOMImplementation interface: document.implementation must inherit property "createDocument(DOMString, DOMString, DocumentType)" with the proper type +PASS DOMImplementation interface: calling createDocument(DOMString, DOMString, DocumentType) on document.implementation with too few arguments must throw TypeError +PASS DOMImplementation interface: document.implementation must inherit property "createHTMLDocument(DOMString)" with the proper type +PASS DOMImplementation interface: calling createHTMLDocument(DOMString) on document.implementation with too few arguments must throw TypeError +PASS DOMImplementation interface: document.implementation must inherit property "hasFeature()" with the proper type +PASS DocumentType interface: existence and properties of interface object +PASS DocumentType interface object length +PASS DocumentType interface object name +PASS DocumentType interface: existence and properties of interface prototype object +PASS DocumentType interface: existence and properties of interface prototype object's "constructor" property +FAIL DocumentType interface: existence and properties of interface prototype object's @@unscopables property assert_false: DocumentType.prototype[Symbol.unscopables] should not be writable expected false got true +PASS DocumentType interface: attribute name +PASS DocumentType interface: attribute publicId +PASS DocumentType interface: attribute systemId +PASS DocumentType interface: operation before([object Object],[object Object]) +PASS DocumentType interface: operation after([object Object],[object Object]) +PASS DocumentType interface: operation replaceWith([object Object],[object Object]) +PASS DocumentType interface: operation remove() +PASS DocumentType must be primary interface of document.doctype +PASS Stringification of document.doctype +PASS DocumentType interface: document.doctype must inherit property "name" with the proper type +PASS DocumentType interface: document.doctype must inherit property "publicId" with the proper type +PASS DocumentType interface: document.doctype must inherit property "systemId" with the proper type +PASS DocumentType interface: document.doctype must inherit property "before([object Object],[object Object])" with the proper type +PASS DocumentType interface: calling before([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError +PASS DocumentType interface: document.doctype must inherit property "after([object Object],[object Object])" with the proper type +PASS DocumentType interface: calling after([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError +PASS DocumentType interface: document.doctype must inherit property "replaceWith([object Object],[object Object])" with the proper type +PASS DocumentType interface: calling replaceWith([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError +PASS DocumentType interface: document.doctype must inherit property "remove()" with the proper type +PASS EventTarget interface: document.doctype must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on document.doctype with too few arguments must throw TypeError +PASS EventTarget interface: document.doctype must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on document.doctype with too few arguments must throw TypeError +PASS EventTarget interface: document.doctype must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on document.doctype with too few arguments must throw TypeError +PASS DocumentFragment interface: existence and properties of interface object +PASS DocumentFragment interface object length +PASS DocumentFragment interface object name +PASS DocumentFragment interface: existence and properties of interface prototype object +PASS DocumentFragment interface: existence and properties of interface prototype object's "constructor" property +FAIL DocumentFragment interface: existence and properties of interface prototype object's @@unscopables property assert_false: DocumentFragment.prototype[Symbol.unscopables] should not be writable expected false got true +PASS DocumentFragment interface: operation getElementById(DOMString) +PASS DocumentFragment interface: attribute children +PASS DocumentFragment interface: attribute firstElementChild +PASS DocumentFragment interface: attribute lastElementChild +PASS DocumentFragment interface: attribute childElementCount +PASS DocumentFragment interface: operation prepend([object Object],[object Object]) +PASS DocumentFragment interface: operation append([object Object],[object Object]) +PASS DocumentFragment interface: operation querySelector(DOMString) +PASS DocumentFragment interface: operation querySelectorAll(DOMString) +PASS DocumentFragment must be primary interface of document.createDocumentFragment() +PASS Stringification of document.createDocumentFragment() +PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "getElementById(DOMString)" with the proper type +PASS DocumentFragment interface: calling getElementById(DOMString) on document.createDocumentFragment() with too few arguments must throw TypeError +PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "children" with the proper type +PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "firstElementChild" with the proper type +PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "lastElementChild" with the proper type +PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "childElementCount" with the proper type +PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "prepend([object Object],[object Object])" with the proper type +PASS DocumentFragment interface: calling prepend([object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError +PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "append([object Object],[object Object])" with the proper type +PASS DocumentFragment interface: calling append([object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError +PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "querySelector(DOMString)" with the proper type +PASS DocumentFragment interface: calling querySelector(DOMString) on document.createDocumentFragment() with too few arguments must throw TypeError +PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "querySelectorAll(DOMString)" with the proper type +PASS DocumentFragment interface: calling querySelectorAll(DOMString) on document.createDocumentFragment() with too few arguments must throw TypeError +PASS EventTarget interface: document.createDocumentFragment() must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError +PASS EventTarget interface: document.createDocumentFragment() must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError +PASS EventTarget interface: document.createDocumentFragment() must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on document.createDocumentFragment() with too few arguments must throw TypeError +PASS ShadowRoot interface: existence and properties of interface object +PASS ShadowRoot interface object length +PASS ShadowRoot interface object name +PASS ShadowRoot interface: existence and properties of interface prototype object +PASS ShadowRoot interface: existence and properties of interface prototype object's "constructor" property +PASS ShadowRoot interface: existence and properties of interface prototype object's @@unscopables property +PASS ShadowRoot interface: attribute mode +PASS ShadowRoot interface: attribute host +PASS Element interface: existence and properties of interface object +PASS Element interface object length +PASS Element interface object name +PASS Element interface: existence and properties of interface prototype object +PASS Element interface: existence and properties of interface prototype object's "constructor" property +FAIL Element interface: existence and properties of interface prototype object's @@unscopables property assert_false: Element.prototype[Symbol.unscopables] should not be writable expected false got true +PASS Element interface: attribute namespaceURI +PASS Element interface: attribute prefix +PASS Element interface: attribute localName +PASS Element interface: attribute tagName +PASS Element interface: attribute id +PASS Element interface: attribute className +PASS Element interface: attribute classList +PASS Element interface: attribute slot +PASS Element interface: operation hasAttributes() +PASS Element interface: attribute attributes +PASS Element interface: operation getAttributeNames() +PASS Element interface: operation getAttribute(DOMString) +PASS Element interface: operation getAttributeNS(DOMString, DOMString) +PASS Element interface: operation setAttribute(DOMString, DOMString) +PASS Element interface: operation setAttributeNS(DOMString, DOMString, DOMString) +PASS Element interface: operation removeAttribute(DOMString) +PASS Element interface: operation removeAttributeNS(DOMString, DOMString) +PASS Element interface: operation toggleAttribute(DOMString, boolean) +PASS Element interface: operation hasAttribute(DOMString) +PASS Element interface: operation hasAttributeNS(DOMString, DOMString) +PASS Element interface: operation getAttributeNode(DOMString) +PASS Element interface: operation getAttributeNodeNS(DOMString, DOMString) +PASS Element interface: operation setAttributeNode(Attr) +PASS Element interface: operation setAttributeNodeNS(Attr) +PASS Element interface: operation removeAttributeNode(Attr) +PASS Element interface: operation attachShadow(ShadowRootInit) +PASS Element interface: attribute shadowRoot +PASS Element interface: operation closest(DOMString) +PASS Element interface: operation matches(DOMString) +PASS Element interface: operation webkitMatchesSelector(DOMString) +PASS Element interface: operation getElementsByTagName(DOMString) +PASS Element interface: operation getElementsByTagNameNS(DOMString, DOMString) +PASS Element interface: operation getElementsByClassName(DOMString) +PASS Element interface: operation insertAdjacentElement(DOMString, Element) +PASS Element interface: operation insertAdjacentText(DOMString, DOMString) +PASS Element interface: attribute children +PASS Element interface: attribute firstElementChild +PASS Element interface: attribute lastElementChild +PASS Element interface: attribute childElementCount +PASS Element interface: operation prepend([object Object],[object Object]) +PASS Element interface: operation append([object Object],[object Object]) +PASS Element interface: operation querySelector(DOMString) +PASS Element interface: operation querySelectorAll(DOMString) +PASS Element interface: attribute previousElementSibling +PASS Element interface: attribute nextElementSibling +PASS Element interface: operation before([object Object],[object Object]) +PASS Element interface: operation after([object Object],[object Object]) +PASS Element interface: operation replaceWith([object Object],[object Object]) +PASS Element interface: operation remove() +PASS Element interface: attribute assignedSlot +PASS Element must be primary interface of element +PASS Stringification of element +PASS Element interface: element must inherit property "namespaceURI" with the proper type +PASS Element interface: element must inherit property "prefix" with the proper type +PASS Element interface: element must inherit property "localName" with the proper type +PASS Element interface: element must inherit property "tagName" with the proper type +PASS Element interface: element must inherit property "id" with the proper type +PASS Element interface: element must inherit property "className" with the proper type +PASS Element interface: element must inherit property "classList" with the proper type +PASS Element interface: element must inherit property "slot" with the proper type +PASS Element interface: element must inherit property "hasAttributes()" with the proper type +PASS Element interface: element must inherit property "attributes" with the proper type +PASS Element interface: element must inherit property "getAttributeNames()" with the proper type +PASS Element interface: element must inherit property "getAttribute(DOMString)" with the proper type +PASS Element interface: calling getAttribute(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "getAttributeNS(DOMString, DOMString)" with the proper type +PASS Element interface: calling getAttributeNS(DOMString, DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "setAttribute(DOMString, DOMString)" with the proper type +PASS Element interface: calling setAttribute(DOMString, DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "setAttributeNS(DOMString, DOMString, DOMString)" with the proper type +PASS Element interface: calling setAttributeNS(DOMString, DOMString, DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "removeAttribute(DOMString)" with the proper type +PASS Element interface: calling removeAttribute(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "removeAttributeNS(DOMString, DOMString)" with the proper type +PASS Element interface: calling removeAttributeNS(DOMString, DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "toggleAttribute(DOMString, boolean)" with the proper type +PASS Element interface: calling toggleAttribute(DOMString, boolean) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "hasAttribute(DOMString)" with the proper type +PASS Element interface: calling hasAttribute(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "hasAttributeNS(DOMString, DOMString)" with the proper type +PASS Element interface: calling hasAttributeNS(DOMString, DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "getAttributeNode(DOMString)" with the proper type +PASS Element interface: calling getAttributeNode(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "getAttributeNodeNS(DOMString, DOMString)" with the proper type +PASS Element interface: calling getAttributeNodeNS(DOMString, DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "setAttributeNode(Attr)" with the proper type +PASS Element interface: calling setAttributeNode(Attr) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "setAttributeNodeNS(Attr)" with the proper type +PASS Element interface: calling setAttributeNodeNS(Attr) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "removeAttributeNode(Attr)" with the proper type +PASS Element interface: calling removeAttributeNode(Attr) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "attachShadow(ShadowRootInit)" with the proper type +PASS Element interface: calling attachShadow(ShadowRootInit) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "shadowRoot" with the proper type +PASS Element interface: element must inherit property "closest(DOMString)" with the proper type +PASS Element interface: calling closest(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "matches(DOMString)" with the proper type +PASS Element interface: calling matches(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "webkitMatchesSelector(DOMString)" with the proper type +PASS Element interface: calling webkitMatchesSelector(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "getElementsByTagName(DOMString)" with the proper type +PASS Element interface: calling getElementsByTagName(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "getElementsByTagNameNS(DOMString, DOMString)" with the proper type +PASS Element interface: calling getElementsByTagNameNS(DOMString, DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "getElementsByClassName(DOMString)" with the proper type +PASS Element interface: calling getElementsByClassName(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "insertAdjacentElement(DOMString, Element)" with the proper type +PASS Element interface: calling insertAdjacentElement(DOMString, Element) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "insertAdjacentText(DOMString, DOMString)" with the proper type +PASS Element interface: calling insertAdjacentText(DOMString, DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "children" with the proper type +PASS Element interface: element must inherit property "firstElementChild" with the proper type +PASS Element interface: element must inherit property "lastElementChild" with the proper type +PASS Element interface: element must inherit property "childElementCount" with the proper type +PASS Element interface: element must inherit property "prepend([object Object],[object Object])" with the proper type +PASS Element interface: calling prepend([object Object],[object Object]) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "append([object Object],[object Object])" with the proper type +PASS Element interface: calling append([object Object],[object Object]) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "querySelector(DOMString)" with the proper type +PASS Element interface: calling querySelector(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "querySelectorAll(DOMString)" with the proper type +PASS Element interface: calling querySelectorAll(DOMString) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "previousElementSibling" with the proper type +PASS Element interface: element must inherit property "nextElementSibling" with the proper type +PASS Element interface: element must inherit property "before([object Object],[object Object])" with the proper type +PASS Element interface: calling before([object Object],[object Object]) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "after([object Object],[object Object])" with the proper type +PASS Element interface: calling after([object Object],[object Object]) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "replaceWith([object Object],[object Object])" with the proper type +PASS Element interface: calling replaceWith([object Object],[object Object]) on element with too few arguments must throw TypeError +PASS Element interface: element must inherit property "remove()" with the proper type +PASS Element interface: element must inherit property "assignedSlot" with the proper type +PASS EventTarget interface: element must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on element with too few arguments must throw TypeError +PASS EventTarget interface: element must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on element with too few arguments must throw TypeError +PASS EventTarget interface: element must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on element with too few arguments must throw TypeError +PASS NamedNodeMap interface: existence and properties of interface object +PASS NamedNodeMap interface object length +PASS NamedNodeMap interface object name +PASS NamedNodeMap interface: existence and properties of interface prototype object +PASS NamedNodeMap interface: existence and properties of interface prototype object's "constructor" property +PASS NamedNodeMap interface: existence and properties of interface prototype object's @@unscopables property +PASS NamedNodeMap interface: attribute length +PASS NamedNodeMap interface: operation item(unsigned long) +PASS NamedNodeMap interface: operation getNamedItem(DOMString) +PASS NamedNodeMap interface: operation getNamedItemNS(DOMString, DOMString) +PASS NamedNodeMap interface: operation setNamedItem(Attr) +PASS NamedNodeMap interface: operation setNamedItemNS(Attr) +PASS NamedNodeMap interface: operation removeNamedItem(DOMString) +PASS NamedNodeMap interface: operation removeNamedItemNS(DOMString, DOMString) +PASS Attr interface: existence and properties of interface object +PASS Attr interface object length +PASS Attr interface object name +PASS Attr interface: existence and properties of interface prototype object +PASS Attr interface: existence and properties of interface prototype object's "constructor" property +PASS Attr interface: existence and properties of interface prototype object's @@unscopables property +PASS Attr interface: attribute namespaceURI +PASS Attr interface: attribute prefix +PASS Attr interface: attribute localName +PASS Attr interface: attribute name +PASS Attr interface: attribute value +PASS Attr interface: attribute ownerElement +PASS Attr interface: attribute specified +PASS Attr must be primary interface of document.querySelector("[id]").attributes[0] +PASS Stringification of document.querySelector("[id]").attributes[0] +PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "namespaceURI" with the proper type +PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "prefix" with the proper type +PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "localName" with the proper type +PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "name" with the proper type +PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "value" with the proper type +PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "ownerElement" with the proper type +PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "specified" with the proper type +PASS EventTarget interface: document.querySelector("[id]").attributes[0] must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on document.querySelector("[id]").attributes[0] with too few arguments must throw TypeError +PASS EventTarget interface: document.querySelector("[id]").attributes[0] must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on document.querySelector("[id]").attributes[0] with too few arguments must throw TypeError +PASS EventTarget interface: document.querySelector("[id]").attributes[0] must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on document.querySelector("[id]").attributes[0] with too few arguments must throw TypeError +PASS CharacterData interface: existence and properties of interface object +PASS CharacterData interface object length +PASS CharacterData interface object name +PASS CharacterData interface: existence and properties of interface prototype object +PASS CharacterData interface: existence and properties of interface prototype object's "constructor" property +FAIL CharacterData interface: existence and properties of interface prototype object's @@unscopables property assert_false: CharacterData.prototype[Symbol.unscopables] should not be writable expected false got true +PASS CharacterData interface: attribute data +PASS CharacterData interface: attribute length +PASS CharacterData interface: operation substringData(unsigned long, unsigned long) +PASS CharacterData interface: operation appendData(DOMString) +PASS CharacterData interface: operation insertData(unsigned long, DOMString) +PASS CharacterData interface: operation deleteData(unsigned long, unsigned long) +PASS CharacterData interface: operation replaceData(unsigned long, unsigned long, DOMString) +PASS CharacterData interface: attribute previousElementSibling +PASS CharacterData interface: attribute nextElementSibling +PASS CharacterData interface: operation before([object Object],[object Object]) +PASS CharacterData interface: operation after([object Object],[object Object]) +PASS CharacterData interface: operation replaceWith([object Object],[object Object]) +PASS CharacterData interface: operation remove() +PASS Text interface: existence and properties of interface object +PASS Text interface object length +PASS Text interface object name +PASS Text interface: existence and properties of interface prototype object +PASS Text interface: existence and properties of interface prototype object's "constructor" property +PASS Text interface: existence and properties of interface prototype object's @@unscopables property +PASS Text interface: operation splitText(unsigned long) +PASS Text interface: attribute wholeText +PASS Text interface: attribute assignedSlot +PASS Text must be primary interface of document.createTextNode("abc") +PASS Stringification of document.createTextNode("abc") +PASS Text interface: document.createTextNode("abc") must inherit property "splitText(unsigned long)" with the proper type +PASS Text interface: calling splitText(unsigned long) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS Text interface: document.createTextNode("abc") must inherit property "wholeText" with the proper type +PASS Text interface: document.createTextNode("abc") must inherit property "assignedSlot" with the proper type +PASS CharacterData interface: document.createTextNode("abc") must inherit property "data" with the proper type +PASS CharacterData interface: document.createTextNode("abc") must inherit property "length" with the proper type +PASS CharacterData interface: document.createTextNode("abc") must inherit property "substringData(unsigned long, unsigned long)" with the proper type +PASS CharacterData interface: calling substringData(unsigned long, unsigned long) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createTextNode("abc") must inherit property "appendData(DOMString)" with the proper type +PASS CharacterData interface: calling appendData(DOMString) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createTextNode("abc") must inherit property "insertData(unsigned long, DOMString)" with the proper type +PASS CharacterData interface: calling insertData(unsigned long, DOMString) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createTextNode("abc") must inherit property "deleteData(unsigned long, unsigned long)" with the proper type +PASS CharacterData interface: calling deleteData(unsigned long, unsigned long) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createTextNode("abc") must inherit property "replaceData(unsigned long, unsigned long, DOMString)" with the proper type +PASS CharacterData interface: calling replaceData(unsigned long, unsigned long, DOMString) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createTextNode("abc") must inherit property "previousElementSibling" with the proper type +PASS CharacterData interface: document.createTextNode("abc") must inherit property "nextElementSibling" with the proper type +PASS CharacterData interface: document.createTextNode("abc") must inherit property "before([object Object],[object Object])" with the proper type +PASS CharacterData interface: calling before([object Object],[object Object]) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createTextNode("abc") must inherit property "after([object Object],[object Object])" with the proper type +PASS CharacterData interface: calling after([object Object],[object Object]) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createTextNode("abc") must inherit property "replaceWith([object Object],[object Object])" with the proper type +PASS CharacterData interface: calling replaceWith([object Object],[object Object]) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createTextNode("abc") must inherit property "remove()" with the proper type +PASS EventTarget interface: document.createTextNode("abc") must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS EventTarget interface: document.createTextNode("abc") must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS EventTarget interface: document.createTextNode("abc") must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on document.createTextNode("abc") with too few arguments must throw TypeError +PASS CDATASection interface: existence and properties of interface object +PASS CDATASection interface object length +PASS CDATASection interface object name +PASS CDATASection interface: existence and properties of interface prototype object +PASS CDATASection interface: existence and properties of interface prototype object's "constructor" property +PASS CDATASection interface: existence and properties of interface prototype object's @@unscopables property +PASS ProcessingInstruction interface: existence and properties of interface object +PASS ProcessingInstruction interface object length +PASS ProcessingInstruction interface object name +PASS ProcessingInstruction interface: existence and properties of interface prototype object +PASS ProcessingInstruction interface: existence and properties of interface prototype object's "constructor" property +PASS ProcessingInstruction interface: existence and properties of interface prototype object's @@unscopables property +PASS ProcessingInstruction interface: attribute target +PASS ProcessingInstruction must be primary interface of xmlDoc.createProcessingInstruction("abc", "def") +PASS Stringification of xmlDoc.createProcessingInstruction("abc", "def") +PASS ProcessingInstruction interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "target" with the proper type +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "data" with the proper type +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "length" with the proper type +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "substringData(unsigned long, unsigned long)" with the proper type +PASS CharacterData interface: calling substringData(unsigned long, unsigned long) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "appendData(DOMString)" with the proper type +PASS CharacterData interface: calling appendData(DOMString) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "insertData(unsigned long, DOMString)" with the proper type +PASS CharacterData interface: calling insertData(unsigned long, DOMString) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "deleteData(unsigned long, unsigned long)" with the proper type +PASS CharacterData interface: calling deleteData(unsigned long, unsigned long) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "replaceData(unsigned long, unsigned long, DOMString)" with the proper type +PASS CharacterData interface: calling replaceData(unsigned long, unsigned long, DOMString) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "previousElementSibling" with the proper type +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "nextElementSibling" with the proper type +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "before([object Object],[object Object])" with the proper type +PASS CharacterData interface: calling before([object Object],[object Object]) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "after([object Object],[object Object])" with the proper type +PASS CharacterData interface: calling after([object Object],[object Object]) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "replaceWith([object Object],[object Object])" with the proper type +PASS CharacterData interface: calling replaceWith([object Object],[object Object]) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "remove()" with the proper type +PASS EventTarget interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS EventTarget interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS EventTarget interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError +PASS Comment interface: existence and properties of interface object +PASS Comment interface object length +PASS Comment interface object name +PASS Comment interface: existence and properties of interface prototype object +PASS Comment interface: existence and properties of interface prototype object's "constructor" property +PASS Comment interface: existence and properties of interface prototype object's @@unscopables property +PASS Comment must be primary interface of document.createComment("abc") +PASS Stringification of document.createComment("abc") +PASS CharacterData interface: document.createComment("abc") must inherit property "data" with the proper type +PASS CharacterData interface: document.createComment("abc") must inherit property "length" with the proper type +PASS CharacterData interface: document.createComment("abc") must inherit property "substringData(unsigned long, unsigned long)" with the proper type +PASS CharacterData interface: calling substringData(unsigned long, unsigned long) on document.createComment("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createComment("abc") must inherit property "appendData(DOMString)" with the proper type +PASS CharacterData interface: calling appendData(DOMString) on document.createComment("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createComment("abc") must inherit property "insertData(unsigned long, DOMString)" with the proper type +PASS CharacterData interface: calling insertData(unsigned long, DOMString) on document.createComment("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createComment("abc") must inherit property "deleteData(unsigned long, unsigned long)" with the proper type +PASS CharacterData interface: calling deleteData(unsigned long, unsigned long) on document.createComment("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createComment("abc") must inherit property "replaceData(unsigned long, unsigned long, DOMString)" with the proper type +PASS CharacterData interface: calling replaceData(unsigned long, unsigned long, DOMString) on document.createComment("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createComment("abc") must inherit property "previousElementSibling" with the proper type +PASS CharacterData interface: document.createComment("abc") must inherit property "nextElementSibling" with the proper type +PASS CharacterData interface: document.createComment("abc") must inherit property "before([object Object],[object Object])" with the proper type +PASS CharacterData interface: calling before([object Object],[object Object]) on document.createComment("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createComment("abc") must inherit property "after([object Object],[object Object])" with the proper type +PASS CharacterData interface: calling after([object Object],[object Object]) on document.createComment("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createComment("abc") must inherit property "replaceWith([object Object],[object Object])" with the proper type +PASS CharacterData interface: calling replaceWith([object Object],[object Object]) on document.createComment("abc") with too few arguments must throw TypeError +PASS CharacterData interface: document.createComment("abc") must inherit property "remove()" with the proper type +PASS EventTarget interface: document.createComment("abc") must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createComment("abc") with too few arguments must throw TypeError +PASS EventTarget interface: document.createComment("abc") must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type +PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createComment("abc") with too few arguments must throw TypeError +PASS EventTarget interface: document.createComment("abc") must inherit property "dispatchEvent(Event)" with the proper type +PASS EventTarget interface: calling dispatchEvent(Event) on document.createComment("abc") with too few arguments must throw TypeError +FAIL AbstractRange interface: existence and properties of interface object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL AbstractRange interface object length assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL AbstractRange interface object name assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL AbstractRange interface: existence and properties of interface prototype object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL AbstractRange interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL AbstractRange interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL AbstractRange interface: attribute startContainer assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL AbstractRange interface: attribute startOffset assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL AbstractRange interface: attribute endContainer assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL AbstractRange interface: attribute endOffset assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL AbstractRange interface: attribute collapsed assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +FAIL StaticRange interface: existence and properties of interface object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +PASS StaticRange interface object length +PASS StaticRange interface object name +FAIL StaticRange interface: existence and properties of interface prototype object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +PASS StaticRange interface: existence and properties of interface prototype object's "constructor" property +PASS StaticRange interface: existence and properties of interface prototype object's @@unscopables property +FAIL Range interface: existence and properties of interface object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +PASS Range interface object length +PASS Range interface object name +FAIL Range interface: existence and properties of interface prototype object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing +PASS Range interface: existence and properties of interface prototype object's "constructor" property +PASS Range interface: existence and properties of interface prototype object's @@unscopables property +PASS Range interface: attribute commonAncestorContainer +PASS Range interface: operation setStart(Node, unsigned long) +PASS Range interface: operation setEnd(Node, unsigned long) +PASS Range interface: operation setStartBefore(Node) +PASS Range interface: operation setStartAfter(Node) +PASS Range interface: operation setEndBefore(Node) +PASS Range interface: operation setEndAfter(Node) +PASS Range interface: operation collapse(boolean) +PASS Range interface: operation selectNode(Node) +PASS Range interface: operation selectNodeContents(Node) +PASS Range interface: constant START_TO_START on interface object +PASS Range interface: constant START_TO_START on interface prototype object +PASS Range interface: constant START_TO_END on interface object +PASS Range interface: constant START_TO_END on interface prototype object +PASS Range interface: constant END_TO_END on interface object +PASS Range interface: constant END_TO_END on interface prototype object +PASS Range interface: constant END_TO_START on interface object +PASS Range interface: constant END_TO_START on interface prototype object +PASS Range interface: operation compareBoundaryPoints(unsigned short, Range) +PASS Range interface: operation deleteContents() +PASS Range interface: operation extractContents() +PASS Range interface: operation cloneContents() +PASS Range interface: operation insertNode(Node) +PASS Range interface: operation surroundContents(Node) +PASS Range interface: operation cloneRange() +PASS Range interface: operation detach() +PASS Range interface: operation isPointInRange(Node, unsigned long) +PASS Range interface: operation comparePoint(Node, unsigned long) +PASS Range interface: operation intersectsNode(Node) +PASS Range interface: stringifier +PASS Range must be primary interface of document.createRange() +PASS Stringification of document.createRange() +PASS Range interface: document.createRange() must inherit property "commonAncestorContainer" with the proper type +PASS Range interface: document.createRange() must inherit property "setStart(Node, unsigned long)" with the proper type +PASS Range interface: calling setStart(Node, unsigned long) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "setEnd(Node, unsigned long)" with the proper type +PASS Range interface: calling setEnd(Node, unsigned long) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "setStartBefore(Node)" with the proper type +PASS Range interface: calling setStartBefore(Node) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "setStartAfter(Node)" with the proper type +PASS Range interface: calling setStartAfter(Node) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "setEndBefore(Node)" with the proper type +PASS Range interface: calling setEndBefore(Node) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "setEndAfter(Node)" with the proper type +PASS Range interface: calling setEndAfter(Node) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "collapse(boolean)" with the proper type +PASS Range interface: calling collapse(boolean) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "selectNode(Node)" with the proper type +PASS Range interface: calling selectNode(Node) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "selectNodeContents(Node)" with the proper type +PASS Range interface: calling selectNodeContents(Node) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "START_TO_START" with the proper type +PASS Range interface: document.createRange() must inherit property "START_TO_END" with the proper type +PASS Range interface: document.createRange() must inherit property "END_TO_END" with the proper type +PASS Range interface: document.createRange() must inherit property "END_TO_START" with the proper type +PASS Range interface: document.createRange() must inherit property "compareBoundaryPoints(unsigned short, Range)" with the proper type +PASS Range interface: calling compareBoundaryPoints(unsigned short, Range) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "deleteContents()" with the proper type +PASS Range interface: document.createRange() must inherit property "extractContents()" with the proper type +PASS Range interface: document.createRange() must inherit property "cloneContents()" with the proper type +PASS Range interface: document.createRange() must inherit property "insertNode(Node)" with the proper type +PASS Range interface: calling insertNode(Node) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "surroundContents(Node)" with the proper type +PASS Range interface: calling surroundContents(Node) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "cloneRange()" with the proper type +PASS Range interface: document.createRange() must inherit property "detach()" with the proper type +PASS Range interface: document.createRange() must inherit property "isPointInRange(Node, unsigned long)" with the proper type +PASS Range interface: calling isPointInRange(Node, unsigned long) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "comparePoint(Node, unsigned long)" with the proper type +PASS Range interface: calling comparePoint(Node, unsigned long) on document.createRange() with too few arguments must throw TypeError +PASS Range interface: document.createRange() must inherit property "intersectsNode(Node)" with the proper type +PASS Range interface: calling intersectsNode(Node) on document.createRange() with too few arguments must throw TypeError +PASS AbstractRange interface: document.createRange() must inherit property "startContainer" with the proper type +PASS AbstractRange interface: document.createRange() must inherit property "startOffset" with the proper type +PASS AbstractRange interface: document.createRange() must inherit property "endContainer" with the proper type +PASS AbstractRange interface: document.createRange() must inherit property "endOffset" with the proper type +PASS AbstractRange interface: document.createRange() must inherit property "collapsed" with the proper type +PASS Range must be primary interface of detachedRange +PASS Stringification of detachedRange +PASS Range interface: detachedRange must inherit property "commonAncestorContainer" with the proper type +PASS Range interface: detachedRange must inherit property "setStart(Node, unsigned long)" with the proper type +PASS Range interface: calling setStart(Node, unsigned long) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "setEnd(Node, unsigned long)" with the proper type +PASS Range interface: calling setEnd(Node, unsigned long) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "setStartBefore(Node)" with the proper type +PASS Range interface: calling setStartBefore(Node) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "setStartAfter(Node)" with the proper type +PASS Range interface: calling setStartAfter(Node) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "setEndBefore(Node)" with the proper type +PASS Range interface: calling setEndBefore(Node) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "setEndAfter(Node)" with the proper type +PASS Range interface: calling setEndAfter(Node) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "collapse(boolean)" with the proper type +PASS Range interface: calling collapse(boolean) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "selectNode(Node)" with the proper type +PASS Range interface: calling selectNode(Node) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "selectNodeContents(Node)" with the proper type +PASS Range interface: calling selectNodeContents(Node) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "START_TO_START" with the proper type +PASS Range interface: detachedRange must inherit property "START_TO_END" with the proper type +PASS Range interface: detachedRange must inherit property "END_TO_END" with the proper type +PASS Range interface: detachedRange must inherit property "END_TO_START" with the proper type +PASS Range interface: detachedRange must inherit property "compareBoundaryPoints(unsigned short, Range)" with the proper type +PASS Range interface: calling compareBoundaryPoints(unsigned short, Range) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "deleteContents()" with the proper type +PASS Range interface: detachedRange must inherit property "extractContents()" with the proper type +PASS Range interface: detachedRange must inherit property "cloneContents()" with the proper type +PASS Range interface: detachedRange must inherit property "insertNode(Node)" with the proper type +PASS Range interface: calling insertNode(Node) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "surroundContents(Node)" with the proper type +PASS Range interface: calling surroundContents(Node) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "cloneRange()" with the proper type +PASS Range interface: detachedRange must inherit property "detach()" with the proper type +PASS Range interface: detachedRange must inherit property "isPointInRange(Node, unsigned long)" with the proper type +PASS Range interface: calling isPointInRange(Node, unsigned long) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "comparePoint(Node, unsigned long)" with the proper type +PASS Range interface: calling comparePoint(Node, unsigned long) on detachedRange with too few arguments must throw TypeError +PASS Range interface: detachedRange must inherit property "intersectsNode(Node)" with the proper type +PASS Range interface: calling intersectsNode(Node) on detachedRange with too few arguments must throw TypeError +PASS AbstractRange interface: detachedRange must inherit property "startContainer" with the proper type +PASS AbstractRange interface: detachedRange must inherit property "startOffset" with the proper type +PASS AbstractRange interface: detachedRange must inherit property "endContainer" with the proper type +PASS AbstractRange interface: detachedRange must inherit property "endOffset" with the proper type +PASS AbstractRange interface: detachedRange must inherit property "collapsed" with the proper type +PASS NodeIterator interface: existence and properties of interface object +PASS NodeIterator interface object length +PASS NodeIterator interface object name +PASS NodeIterator interface: existence and properties of interface prototype object +PASS NodeIterator interface: existence and properties of interface prototype object's "constructor" property +PASS NodeIterator interface: existence and properties of interface prototype object's @@unscopables property +PASS NodeIterator interface: attribute root +PASS NodeIterator interface: attribute referenceNode +PASS NodeIterator interface: attribute pointerBeforeReferenceNode +PASS NodeIterator interface: attribute whatToShow +PASS NodeIterator interface: attribute filter +PASS NodeIterator interface: operation nextNode() +PASS NodeIterator interface: operation previousNode() +PASS NodeIterator interface: operation detach() +PASS NodeIterator must be primary interface of document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) +PASS Stringification of document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) +PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "root" with the proper type +PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "referenceNode" with the proper type +PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "pointerBeforeReferenceNode" with the proper type +PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "whatToShow" with the proper type +PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "filter" with the proper type +PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "nextNode()" with the proper type +PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "previousNode()" with the proper type +PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "detach()" with the proper type +PASS TreeWalker interface: existence and properties of interface object +PASS TreeWalker interface object length +PASS TreeWalker interface object name +PASS TreeWalker interface: existence and properties of interface prototype object +PASS TreeWalker interface: existence and properties of interface prototype object's "constructor" property +PASS TreeWalker interface: existence and properties of interface prototype object's @@unscopables property +PASS TreeWalker interface: attribute root +PASS TreeWalker interface: attribute whatToShow +PASS TreeWalker interface: attribute filter +PASS TreeWalker interface: attribute currentNode +PASS TreeWalker interface: operation parentNode() +PASS TreeWalker interface: operation firstChild() +PASS TreeWalker interface: operation lastChild() +PASS TreeWalker interface: operation previousSibling() +PASS TreeWalker interface: operation nextSibling() +PASS TreeWalker interface: operation previousNode() +PASS TreeWalker interface: operation nextNode() +PASS TreeWalker must be primary interface of document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) +PASS Stringification of document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "root" with the proper type +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "whatToShow" with the proper type +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "filter" with the proper type +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "currentNode" with the proper type +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "parentNode()" with the proper type +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "firstChild()" with the proper type +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "lastChild()" with the proper type +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "previousSibling()" with the proper type +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "nextSibling()" with the proper type +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "previousNode()" with the proper type +PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "nextNode()" with the proper type +PASS NodeFilter interface: existence and properties of interface object +PASS NodeFilter interface object name +PASS NodeFilter interface: existence and properties of interface prototype object +PASS NodeFilter interface: existence and properties of interface prototype object's "constructor" property +PASS NodeFilter interface: existence and properties of interface prototype object's @@unscopables property +PASS NodeFilter interface: constant FILTER_ACCEPT on interface object +PASS NodeFilter interface: constant FILTER_ACCEPT on interface prototype object +PASS NodeFilter interface: constant FILTER_REJECT on interface object +PASS NodeFilter interface: constant FILTER_REJECT on interface prototype object +PASS NodeFilter interface: constant FILTER_SKIP on interface object +PASS NodeFilter interface: constant FILTER_SKIP on interface prototype object +PASS NodeFilter interface: constant SHOW_ALL on interface object +PASS NodeFilter interface: constant SHOW_ALL on interface prototype object +PASS NodeFilter interface: constant SHOW_ELEMENT on interface object +PASS NodeFilter interface: constant SHOW_ELEMENT on interface prototype object +PASS NodeFilter interface: constant SHOW_ATTRIBUTE on interface object +PASS NodeFilter interface: constant SHOW_ATTRIBUTE on interface prototype object +PASS NodeFilter interface: constant SHOW_TEXT on interface object +PASS NodeFilter interface: constant SHOW_TEXT on interface prototype object +PASS NodeFilter interface: constant SHOW_CDATA_SECTION on interface object +PASS NodeFilter interface: constant SHOW_CDATA_SECTION on interface prototype object +PASS NodeFilter interface: constant SHOW_ENTITY_REFERENCE on interface object +PASS NodeFilter interface: constant SHOW_ENTITY_REFERENCE on interface prototype object +PASS NodeFilter interface: constant SHOW_ENTITY on interface object +PASS NodeFilter interface: constant SHOW_ENTITY on interface prototype object +PASS NodeFilter interface: constant SHOW_PROCESSING_INSTRUCTION on interface object +PASS NodeFilter interface: constant SHOW_PROCESSING_INSTRUCTION on interface prototype object +PASS NodeFilter interface: constant SHOW_COMMENT on interface object +PASS NodeFilter interface: constant SHOW_COMMENT on interface prototype object +PASS NodeFilter interface: constant SHOW_DOCUMENT on interface object +PASS NodeFilter interface: constant SHOW_DOCUMENT on interface prototype object +PASS NodeFilter interface: constant SHOW_DOCUMENT_TYPE on interface object +PASS NodeFilter interface: constant SHOW_DOCUMENT_TYPE on interface prototype object +PASS NodeFilter interface: constant SHOW_DOCUMENT_FRAGMENT on interface object +PASS NodeFilter interface: constant SHOW_DOCUMENT_FRAGMENT on interface prototype object +PASS NodeFilter interface: constant SHOW_NOTATION on interface object +PASS NodeFilter interface: constant SHOW_NOTATION on interface prototype object +PASS NodeFilter interface: operation acceptNode(Node) +PASS DOMTokenList interface: existence and properties of interface object +PASS DOMTokenList interface object length +PASS DOMTokenList interface object name +PASS DOMTokenList interface: existence and properties of interface prototype object +PASS DOMTokenList interface: existence and properties of interface prototype object's "constructor" property +PASS DOMTokenList interface: existence and properties of interface prototype object's @@unscopables property +PASS DOMTokenList interface: attribute length +PASS DOMTokenList interface: operation item(unsigned long) +PASS DOMTokenList interface: operation contains(DOMString) +PASS DOMTokenList interface: operation add(DOMString) +PASS DOMTokenList interface: operation remove(DOMString) +PASS DOMTokenList interface: operation toggle(DOMString, boolean) +PASS DOMTokenList interface: operation replace(DOMString, DOMString) +PASS DOMTokenList interface: operation supports(DOMString) +PASS DOMTokenList interface: attribute value +PASS DOMTokenList interface: stringifier +PASS DOMTokenList interface: iterable<DOMString> +PASS DOMTokenList must be primary interface of document.body.classList +PASS Stringification of document.body.classList +PASS DOMTokenList interface: document.body.classList must inherit property "length" with the proper type +PASS DOMTokenList interface: document.body.classList must inherit property "item(unsigned long)" with the proper type +PASS DOMTokenList interface: calling item(unsigned long) on document.body.classList with too few arguments must throw TypeError +PASS DOMTokenList interface: document.body.classList must inherit property "contains(DOMString)" with the proper type +PASS DOMTokenList interface: calling contains(DOMString) on document.body.classList with too few arguments must throw TypeError +PASS DOMTokenList interface: document.body.classList must inherit property "add(DOMString)" with the proper type +PASS DOMTokenList interface: calling add(DOMString) on document.body.classList with too few arguments must throw TypeError +PASS DOMTokenList interface: document.body.classList must inherit property "remove(DOMString)" with the proper type +PASS DOMTokenList interface: calling remove(DOMString) on document.body.classList with too few arguments must throw TypeError +PASS DOMTokenList interface: document.body.classList must inherit property "toggle(DOMString, boolean)" with the proper type +PASS DOMTokenList interface: calling toggle(DOMString, boolean) on document.body.classList with too few arguments must throw TypeError +PASS DOMTokenList interface: document.body.classList must inherit property "replace(DOMString, DOMString)" with the proper type +PASS DOMTokenList interface: calling replace(DOMString, DOMString) on document.body.classList with too few arguments must throw TypeError +PASS DOMTokenList interface: document.body.classList must inherit property "supports(DOMString)" with the proper type +PASS DOMTokenList interface: calling supports(DOMString) on document.body.classList with too few arguments must throw TypeError +PASS DOMTokenList interface: document.body.classList must inherit property "value" with the proper type +FAIL Window interface: attribute event assert_true: property should be enumerable expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/dom/interfaces.html b/third_party/blink/web_tests/external/wpt/dom/interfaces.html deleted file mode 100644 index 111608b..0000000 --- a/third_party/blink/web_tests/external/wpt/dom/interfaces.html +++ /dev/null
@@ -1,63 +0,0 @@ -<!doctype html> -<meta charset=utf-8> -<title>DOM IDL tests</title> -<meta name="timeout" content="long"> -<meta name="variant" content="?include=Node"> -<meta name="variant" content="?exclude=Node"> -<script src=/resources/testharness.js></script> -<script src=/resources/testharnessreport.js></script> -<script src=/common/subset-tests-by-key.js></script> -<script src=/resources/WebIDLParser.js></script> -<script src=/resources/idlharness.js></script> - -<h1>DOM IDL tests</h1> -<div id=log></div> -<script> -"use strict"; -var xmlDoc = document.implementation.createDocument(null, "", null); -var detachedRange = document.createRange(); -detachedRange.detach(); -var element = xmlDoc.createElementNS(null, "test"); -element.setAttribute("bar", "baz"); - -var idlArray = new IdlArray(); - -function doTest([html, dom]) { - idlArray.add_idls(dom); - idlArray.add_dependency_idls(html); - idlArray.add_objects({ - EventTarget: ['new EventTarget()'], - Event: ['document.createEvent("Event")', 'new Event("foo")'], - CustomEvent: ['new CustomEvent("foo")'], - AbortController: ['new AbortController()'], - AbortSignal: ['new AbortController().signal'], - Document: ['new Document()'], - XMLDocument: ['xmlDoc'], - DOMImplementation: ['document.implementation'], - DocumentFragment: ['document.createDocumentFragment()'], - DocumentType: ['document.doctype'], - Element: ['element'], - Attr: ['document.querySelector("[id]").attributes[0]'], - Text: ['document.createTextNode("abc")'], - ProcessingInstruction: ['xmlDoc.createProcessingInstruction("abc", "def")'], - Comment: ['document.createComment("abc")'], - Range: ['document.createRange()', 'detachedRange'], - NodeIterator: ['document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false)'], - TreeWalker: ['document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false)'], - NodeList: ['document.querySelectorAll("script")'], - HTMLCollection: ['document.body.children'], - DOMTokenList: ['document.body.classList'], - }); - idlArray.test(); -} - -function fetchText(url) { - return fetch(url).then((response) => response.text()); -} - -promise_test(function() { - return Promise.all(['/interfaces/html.idl', - '/interfaces/dom.idl'].map(fetchText)) - .then(doTest); -}, "Test driver"); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/encrypted-media/idlharness.https.html b/third_party/blink/web_tests/external/wpt/encrypted-media/idlharness.https.html index 6a2ae80a..8050942 100644 --- a/third_party/blink/web_tests/external/wpt/encrypted-media/idlharness.https.html +++ b/third_party/blink/web_tests/external/wpt/encrypted-media/idlharness.https.html
@@ -22,16 +22,19 @@ <script> 'use strict'; - promise_test(async () => { - const idls = await fetch('/interfaces/encrypted-media.idl').then(r => r.text()); - const html = await fetch('/interfaces/html.idl').then(r => r.text()); - const dom = await fetch('/interfaces/dom.idl').then(r => r.text()); - var idl_array = new IdlArray(); - idl_array.add_idls(idls); - idl_array.add_dependency_idls(html); - idl_array.add_dependency_idls(dom); - idl_array.test(); - }, 'Test encrypted-media IDL'); + idl_test( + ['encrypted-media'], + ['html', 'dom'], + idl_array => { + self.audio = document.createElement('audio'); + self.video = document.createElement('video'); + idl_array.add_objects({ + HTMLAudioElement: ['audio'], + HTMLVideoElement: ['video'], + Navigator: ['navigator'], + }); + } + ); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/bufferbeforeonload.html b/third_party/blink/web_tests/external/wpt/event-timing/bufferbeforeonload.html deleted file mode 100644 index 4b003a9..0000000 --- a/third_party/blink/web_tests/external/wpt/event-timing/bufferbeforeonload.html +++ /dev/null
@@ -1,99 +0,0 @@ -<!DOCTYPE html> -<html> -<meta charset=utf-8 /> -<title>Event Timing: buffer long-latency events before onload</title> -<meta name="timeout" content="long"> -<button id='button' onmousedown='clickDelay()'>Generate a 'click' event</button> -<script src=/resources/testharness.js></script> -<script src=/resources/testharnessreport.js></script> -<script src=/resources/testdriver.js></script> -<script src=/resources/testdriver-vendor.js></script> - -<script src=resources/event-timing-test-utils.js></script> -<img src=resources/slow-image.py> - -<script> - let clickTimeMin; - let processingStartMin; - let onloadStart; - let firstClickStart = 0; - let firstClickEnd = 0; - function clickDelay() { - const onclickStart = performance.now(); - if (firstClickStart === 0) - firstClickStart = onclickStart; - while(performance.now() < onclickStart + 60) {} - if (firstClickEnd === 0) - firstClickEnd = performance.now(); - } - - function validateEntries(entries) { - const entriesBeforeOnload = entries.filter( - e => e.startTime < onloadStart); - assert_equals(entriesBeforeOnload.length, 1, - "Long latency events before onload should be buffered."); - const entry = entriesBeforeOnload[0]; - verifyClickEvent(entry, true); - - assert_greater_than_equal(entry.startTime, clickTimeMin, - "The entry's start time should be later than clickTimeMin."); - assert_greater_than_equal(entry.processingStart, processingStartMin, - "The entry should be processed later than processingStartMin."); - assert_less_than_equal(entry.processingStart, firstClickStart, - "The processingStart must be before firstClickStart.") - assert_greater_than_equal(entry.processingEnd, firstClickEnd, - "The processingEnd must be after firstClickEnd."); - - const entriesAfterOnload = entries.filter( - e => e.startTime >= onloadStart); - assert_equals(entriesAfterOnload.length, 1, - "Events after onload should still be buffered."); - } - - /* Timeline: - Begin Busy Loop - Click 1 arrives - End Busy Loop - (Dispatch and Process Click 1 - buffered) - Onload Event Fires - Begin Busy Loop - Click 2 arrives - End Busy Loop - (Dispatch and Process Click 2 - not buffered) - */ - async_test(function(t) { - if (!window.PerformanceEventTiming) - assert_unreached("PerformanceEventTiming is not supported"); - - clickTimeMin = performance.now(); - clickAndBlockMain('button'); - // Event handlers will be dispatched asynchronously, so this will be called - // before processing begins. - processingStartMin = performance.now(); - const bufferedEntries = []; - on_event(window, 'load', e => { - onloadStart = performance.now(); - // Register the observer after the page has been loaded - const observer = new PerformanceObserver(function (entryList, observer) { - entryList.getEntries().forEach(function(entry) { - assert_equals(entry.entryType, "event"); - if (entry.name === 'mousedown') { - bufferedEntries.push(entry); - } - if (bufferedEntries.length == 2) { - validateEntries(bufferedEntries) - observer.disconnect(); - t.done(); - } - }); - }) - observer.observe({ - type: "event", - buffered: true - }); - clickAndBlockMain('button'); - }); - }, "Event Timing: click, onload."); - -</script> -</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/click-timing.html b/third_party/blink/web_tests/external/wpt/event-timing/click-timing.html new file mode 100644 index 0000000..afe53bfc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/event-timing/click-timing.html
@@ -0,0 +1,64 @@ +<!DOCTYPE html> +<html> +<meta charset=utf-8 /> +<title>Event Timing: compare timing of two long clicks +</title> +<button id='button'>Generate a 'click' event</button> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/resources/testdriver.js></script> +<script src=/resources/testdriver-vendor.js></script> +<script src=resources/event-timing-test-utils.js></script> +<script> + /* Timeline: + Observer starts + Long click 1 + Long click 2 + Once two clicks have been received by observer, compare the timestamps. + */ + let timeBeforeFirstClick; + let timeAfterFirstClick; + let timeAfterSecondClick; + let observedEntries = []; + async_test(function(t) { + if (!window.PerformanceEventTiming) + assert_unreached("PerformanceEventTiming is not supported"); + + new PerformanceObserver(t.step_func(entryList => { + observedEntries = observedEntries.concat(entryList.getEntries().filter( + entry => entry.name === 'mousedown')); + if (observedEntries.length < 2) + return; + + assert_not_equals(timeBeforeFirstClick, undefined); + assert_not_equals(timeAfterFirstClick, undefined); + assert_not_equals(timeAfterSecondClick, undefined); + // First click. + verifyClickEvent(observedEntries[0]); + assert_between_exclusive(observedEntries[0].processingStart, + timeBeforeFirstClick, + timeAfterFirstClick, + "First click's processingStart"); + assert_greater_than(timeAfterFirstClick, observedEntries[0].startTime, + "timeAfterFirstClick should be later than first click's start time."); + + // Second click. + verifyClickEvent(observedEntries[1]); + assert_between_exclusive(observedEntries[1].processingStart, + timeAfterFirstClick, + timeAfterSecondClick, + "Second click's processingStart"); + assert_greater_than(timeAfterSecondClick, observedEntries[1].startTime, + "timeAfterSecondClick should be later than second click's start time."); + t.done(); + })).observe({type: 'event'}); + timeBeforeFirstClick = performance.now(); + clickAndBlockMain('button').then( () => { + timeAfterFirstClick = performance.now(); + clickAndBlockMain('button').then(() => { + timeAfterSecondClick = performance.now(); + }) + }); + }, "Event Timing: compare click timings."); +</script> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/observethenonload.html b/third_party/blink/web_tests/external/wpt/event-timing/observethenonload.html deleted file mode 100644 index 8295aaf..0000000 --- a/third_party/blink/web_tests/external/wpt/event-timing/observethenonload.html +++ /dev/null
@@ -1,97 +0,0 @@ -<!DOCTYPE html> -<html> -<meta charset=utf-8 /> -<title>Event Timing: Performance observers can observe long-latency events -</title> -<meta name="timeout" content="long"> -<button id='button'>Generate a 'click' event</button> -<script src=/resources/testharness.js></script> -<script src=/resources/testharnessreport.js></script> -<script src=/resources/testdriver.js></script> -<script src=/resources/testdriver-vendor.js></script> - -<script src=resources/event-timing-test-utils.js></script> -<img src=resources/slow-image.py> - -<script> - let timeBeforeFirstClick; - let timeAfterFirstClick; - let timeAfterSecondClick; - let onloadStart; - let observedEntries = []; - - function verifyObserverEntries(observedEntries) { - const entriesAfterFirstClick = observedEntries.filter( - e => e.startTime > timeAfterFirstClick); - assert_equals(entriesAfterFirstClick.length, 1, - 'There should be one event after timeAfterFirstClick.'); - const entry1 = entriesAfterFirstClick[0]; - verifyClickEvent(entry1); - assert_greater_than(entry1.processingStart, timeAfterFirstClick, - "entry1's processing start should be after timeAfterFirstClick"); - assert_less_than(entry1.processingStart, timeAfterSecondClick, - "entry1's processing start should be before timeAfterSecondClick."); - assert_greater_than(entry1.startTime, onloadStart, - "entry1's start time should be later than onloadStart."); - - const entriesBeforeFirstClick = - observedEntries.filter(e => e.startTime < timeAfterFirstClick); - assert_equals(entriesBeforeFirstClick.length, 1, - 'There should be one event before timeAfterFirstClick.' - ); - const entry2 = entriesBeforeFirstClick[0]; - verifyClickEvent(entry2); - assert_greater_than(entry2.processingStart, timeBeforeFirstClick, - "entry2's processing start should be after timeBeforeFirstClick"); - assert_less_than(entry2.processingStart, timeAfterFirstClick, - "entry2's processing start should be berfore timeAfterFirstClick."); - assert_greater_than(timeAfterFirstClick, entry2.startTime, - "timeAfterFirstClick should be later than entry2's start time."); - // This should happen before onLoad - assert_greater_than(onloadStart, entry2.startTime, - "Onload should be later than entry's start time."); - } - - /* Timeline: - Observer starts - Begin Busy Loop - Click 1 arrives - End Busy Loop - (Dispatch and Process Click 1 (buffered, observed)) - Onload Event Fires - Begin Busy Loop - Click 2 arrives - End Busy Loop - (Dispatch and Process Click 2 (buffered, observed)) - observer callback start - */ - async_test(function(t) { - if (!window.PerformanceEventTiming) - assert_unreached("PerformanceEventTiming is not supported"); - - const observerPromise = new Promise((resolve, reject) => { - new PerformanceObserver(function(entryList) { - observedEntries = observedEntries.concat(entryList.getEntries().filter( - entry => entry.name === 'mousedown')); - if (observedEntries.length < 2) return; - resolve(observedEntries); - }).observe({ type: 'event' , buffered: true}); - }); - timeBeforeFirstClick = performance.now(); - clickAndBlockMain('button').then( () => { - timeAfterFirstClick = performance.now(); - }); - on_event(window, 'load', function(e) { - onloadStart = performance.now(); - // After onload start and before registering observer. - const bufferPromise = clickAndBlockMain('button').then(wait); - Promise.all([observerPromise, bufferPromise]).then((results) => { - timeAfterSecondClick = performance.now(); - t.step(verifyObserverEntries.bind(null, results[0])); - t.done(); - }); - }); - }, "Event Timing: click, observer, onload, click."); - -</script> -</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve-firstInput.html b/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve-firstInput.html deleted file mode 100644 index 3cd80e2..0000000 --- a/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve-firstInput.html +++ /dev/null
@@ -1,66 +0,0 @@ -<!DOCTYPE html> -<html> -<meta charset=utf-8 /> -<title>Event Timing: buffer long-latency events before onload</title> -<meta name="timeout" content="long"> -<button id='button'>Generate a 'click' event</button> -<script src=/resources/testharness.js></script> -<script src=/resources/testharnessreport.js></script> -<script src=/resources/testdriver.js></script> -<script src=/resources/testdriver-vendor.js></script> - -<script src=resources/event-timing-test-utils.js></script> - -<script> - /* Timeline: - Onload - PerformanceObserver is registered - Click 1 - Click 2 - PerformanceObserver should observe only one first-input entry. - (Dispatch and Process Click 2 - not buffered) - */ - async_test(function(t) { - if (!window.PerformanceEventTiming) - assert_unreached("PerformanceEventTiming is not supported"); - - let numFirstInputObserved = 0; - let numEventsObserved = 0; - let observedEventEntries = []; - - const event_observer_promise = new Promise((resolve, reject) => { - new PerformanceObserver(function(entryList) { - observedEventEntries = entryList.getEntries().filter( - entry => entry.name === 'mousedown'); - numEventsObserved += observedEventEntries.length; - if (numEventsObserved >= 2) { - // There should be 2 event entries. - assert_equals(numEventsObserved, 2, - "There should be 2 observed event entries."); - resolve(); - } - }).observe({ type: 'event' , buffered: true}); - }); - - const first_input_observer_promise = new Promise((resolve, reject) => { - new PerformanceObserver(function(entryList) { - assert_equals(entryList.getEntries().length, 1); - resolve(); - }).observe({ type: 'first-input' , buffered: true}); - }); - - on_event(window, 'load', function(e) { - const click_promise = clickAndBlockMain('button').then(() => { - clickAndBlockMain('button'); - }); - Promise.all( - [event_observer_promise, first_input_observer_promise, click_promise] - ).then(() => { - t.done(); - }); - }); - }, - "Event Timing: check first-input after onload, observer, click, click." - ); -</script> -</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve.html b/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve.html deleted file mode 100644 index 4365f48..0000000 --- a/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve.html +++ /dev/null
@@ -1,80 +0,0 @@ -<!DOCTYPE html> -<html> -<meta charset=utf-8 /> -<title>Event Timing: long-latency events after onload and before observer -registration are lost -</title> -<meta name="timeout" content="long"> -<button id='button'>Generate a 'click' event</button> -<script src=/resources/testharness.js></script> -<script src=/resources/testharnessreport.js></script> -<script src=/resources/testdriver.js></script> -<script src=/resources/testdriver-vendor.js></script> - -<script src=resources/event-timing-test-utils.js></script> -<script> - let callbackTime; - let observerStart; - let processingStartMin; - - function verifyObserverEntries(observedEntries) { - // Verify observer entries. Should not include first click since we didn't - // buffered to true. - assert_equals(observedEntries.length, 1, "Long latency task after observer start should be observed."); - const entry = observedEntries[0]; - verifyClickEvent(entry); - assert_greater_than(entry.processingStart, processingStartMin, - "The entry's processing start should be later than processingStartMin."); - assert_greater_than(callbackTime, entry.processingStart, - "The callback time should be later than the entry's processing start."); - assert_greater_than(entry.startTime, observerStart, - "The entry's start time should be later than observer start."); - assert_greater_than(callbackTime, entry.startTime, - "The callback time should be later than entry's start time."); - } - - function startObserver(t) { - new PerformanceObserver(t.step_func_done((entryList, obs) => { - callbackTime = performance.now(); - const observedEntries = entryList.getEntries().filter( - entry => entry.name === 'mousedown'); - verifyObserverEntries(observedEntries); - })).observe({ type: 'event'}); - observerStart = performance.now(); - } - - /* Timeline: - Onload Event fires - Begin Busy Loop - Click 1 arrives - End Busy Loop - (Dispatch and Process Click 1 (not buffered, not observed)) - Observer start - Begin Busy Loop - Click 2 arrives - End Busy Loop - (Dispatch and Process Click 2 (not buffered, observed)) - */ - async_test(function(t) { - if (!window.PerformanceEventTiming) - assert_unreached("PerformanceEventTiming is not supported"); - - // Use a dummy observer to know when the first click has been dispatched. - const observerPromise = new Promise((resolve, reject) => { - new PerformanceObserver((entryList, observer) => { - resolve(); - observer.disconnect(); - }).observe({ entryTypes: ['event'] }); - }); - on_event(window, 'load', () => { - const clickPromise = clickAndBlockMain('button'); - Promise.all([observerPromise, clickPromise]).then(() => { - startObserver(t); - clickAndBlockMain('button'); - processingStartMin = performance.now(); - }); - }); - },"Event Timing: onload, click, observer, click."); - -</script> -</html>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.window.js b/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.window.js index f8c92c1..fe4ac88 100644 --- a/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.window.js +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.window.js
@@ -3,16 +3,15 @@ // https://www.w3.org/TR/geolocation-API/ -promise_test(async () => { - const idl = await fetch('/interfaces/geolocation-API.idl').then(r => r.text()); - const html = await fetch('/interfaces/html.idl').then(r => r.text()); - - const idl_array = new IdlArray(); - idl_array.add_idls(idl); - idl_array.add_dependency_idls(html); - idl_array.add_objects({ - Navigator: ["navigator"], - Geolocation: ["navigator.geolocation"] - }); - idl_array.test(); -}, 'geolocation-API interfaces'); +idl_test( + ['geolocation-API'], + ['html'], + idl_array => { + self.audio = document.createElement('audio'); + self.video = document.createElement('video'); + idl_array.add_objects({ + Navigator: ['navigator'], + Geolocation: ['navigator.geolocation'], + }); + } +);
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-depth/idlharness.html b/third_party/blink/web_tests/external/wpt/mediacapture-depth/idlharness.html index 1afc6e5..963229aa 100644 --- a/third_party/blink/web_tests/external/wpt/mediacapture-depth/idlharness.html +++ b/third_party/blink/web_tests/external/wpt/mediacapture-depth/idlharness.html
@@ -4,7 +4,7 @@ <head> <meta charset=utf-8> <title>Media Capture Depth Stream Extensions IDL test</title> - <link rel="help" href="See https://w3c.github.io/mediacapture-depth/"> + <link rel="help" href="https://w3c.github.io/mediacapture-depth/"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/resources/WebIDLParser.js"></script> @@ -15,15 +15,13 @@ <script> 'use strict'; - promise_test(async () => { - const idl = await fetch('/interfaces/mediacapture-depth.idl').then(r => r.text()); - const main = await fetch('/interfaces/mediacapture-streams.idl').then(r => r.text()); - - var idl_array = new IdlArray(); - idl_array.add_idls(idl); - idl_array.add_dependency_idls(main); - idl_array.test(); - }, 'mediacapture-depth interfaces'); + idl_test( + ['mediacapture-depth'], + ['mediacapture-streams'], + idl_array => { + // No objects, spec defines dictionaries only. + } + ); </script> <div id="log"></div> </body>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js index 5b255fca..594e112 100644 --- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js +++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js
@@ -5,50 +5,44 @@ // https://w3c.github.io/mediacapture-main/ - -promise_test(async () => { - const srcs = ['mediacapture-streams','dom','html']; - const [idl, dom, html] = await Promise.all( - srcs.map(i => fetch(`/interfaces/${i}.idl`).then(r => r.text()))); - - const idl_array = new IdlArray(); - idl_array.add_idls(idl); - idl_array.add_dependency_idls(html); - idl_array.add_dependency_idls(dom); - - const devices = []; - // Errors will be surfaced in idlharness.js's test_object below. - try { - const list = await navigator.mediaDevices.enumerateDevices(); - for (const item of list) { - switch (item.kind) { - case 'audioinput': - case 'videoinput': - case 'audiooutput': - self[item.kind] = item; - devices.push(item.kind); - default: - assert_unreached( - 'media.kind should be one of "audioinput", "videoinput", or "audiooutput".'); +idl_test( + ['mediacapture-streams'], + ['dom', 'html'], + async idl_array => { + const inputDevices = []; + const outputDevices = []; + try { + const list = await navigator.mediaDevices.enumerateDevices(); + for (const device of list) { + if (device.kind in self) { + continue; + } + assert_in_array(device.kind, ['audioinput', 'videoinput', 'audiooutput']); + self[device.kind] = device; + if (device.kind.endsWith('input')) { + inputDevices.push(device.kind); + } else { + outputDevices.push(device.kind); + } } - } - } catch (e) {} + } catch (e) {} - try { - self.stream = await navigator.mediaDevices.getUserMedia({audio: true}); - self.track = stream.getTracks()[0]; - self.trackEvent = new MediaStreamTrackEvent("type", { - track: track, + try { + self.stream = await navigator.mediaDevices.getUserMedia({audio: true}); + self.track = stream.getTracks()[0]; + self.trackEvent = new MediaStreamTrackEvent("type", { + track: track, + }); + } catch (e) {} + + idl_array.add_objects({ + InputDeviceInfo: inputDevices, + MediaStream: ['stream', 'new MediaStream()'], + Navigator: ['navigator'], + MediaDevices: ['navigator.mediaDevices'], + MediaDeviceInfo: outputDevices, + MediaStreamTrack: ['track'], + MediaStreamTrackEvent: ['trackEvent'], }); - } catch (e) { throw e} - - idl_array.add_objects({ - InputDeviceInfo: devices, - MediaStream: ['stream', 'new MediaStream()'], - Navigator: ['navigator'], - MediaDevices: ['navigator.mediaDevices'], - MediaStreamTrack: ['track'], - MediaStreamTrackEvent: ['trackEvent'], - }); - idl_array.test(); -}, 'mediacapture-streams interfaces.'); + } +);
diff --git a/third_party/blink/web_tests/external/wpt/orientation-event/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/orientation-event/idlharness.https.window.js index ed8309d6..55cfed92 100644 --- a/third_party/blink/web_tests/external/wpt/orientation-event/idlharness.https.window.js +++ b/third_party/blink/web_tests/external/wpt/orientation-event/idlharness.https.window.js
@@ -5,19 +5,14 @@ 'use strict'; -promise_test(async () => { - const idl = await fetch('/interfaces/orientation-event.idl').then(r => r.text()); - const dom = await fetch('/interfaces/dom.idl').then(r => r.text()); - const html = await fetch('/interfaces/html.idl').then(r => r.text()); - - var idl_array = new IdlArray(); - idl_array.add_idls(idl); - idl_array.add_dependency_idls(html); - idl_array.add_dependency_idls(dom); - idl_array.add_objects({ - Window: ['window'], - DeviceOrientationEvent: ['new DeviceOrientationEvent("foo")'], - DeviceMotionEvent: ['new DeviceMotionEvent("foo")'], - }); - idl_array.test(); -}, 'orientation-event interfaces'); +idl_test( + ['orientation-event'], + ['html', 'dom'], + idl_array => { + idl_array.add_objects({ + Window: ['window'], + DeviceOrientationEvent: ['new DeviceOrientationEvent("foo")'], + DeviceMotionEvent: ['new DeviceMotionEvent("foo")'], + }); + } +);
diff --git a/third_party/blink/web_tests/external/wpt/permissions/interfaces.any.js b/third_party/blink/web_tests/external/wpt/permissions/interfaces.any.js index b9345388..ff0a969b 100644 --- a/third_party/blink/web_tests/external/wpt/permissions/interfaces.any.js +++ b/third_party/blink/web_tests/external/wpt/permissions/interfaces.any.js
@@ -1,41 +1,27 @@ // META: script=/resources/WebIDLParser.js // META: script=/resources/idlharness.js -"use strict"; - -if (self.importScripts) { - importScripts("/resources/testharness.js"); - importScripts("/resources/WebIDLParser.js", "/resources/idlharness.js"); -} - // https://w3c.github.io/permissions/#idl-index -promise_test(async () => { - const idl = await fetch("/interfaces/permissions.idl").then(r => r.text()); - const dom = await fetch("/interfaces/dom.idl").then(r => r.text()); - const html = await fetch("/interfaces/html.idl").then(r => r.text()); +"use strict"; - const idl_array = new IdlArray(); - idl_array.add_idls(idl); - idl_array.add_dependency_idls(dom); - idl_array.add_dependency_idls(html); +idl_test( + ['permissions'], + ['html', 'dom'], + async idl_array => { + try { + self.permissionStatus = await navigator.permissions.query({ name: "geolocation" }); + } catch (e) {} - try { - self.permissionStatus = await navigator.permissions.query({ name: "geolocation" }); - self.permissionStatus = await navigator.permissions.query({ name: "background-fetch" }); - } catch (e) { - // Will be surfaced in idlharness.js's test_object below. + if (self.GLOBAL.isWorker()) { + idl_array.add_objects({ WorkerNavigator: ['navigator'] }); + } else { + idl_array.add_objects({ Navigator: ['navigator'] }); + } + + idl_array.add_objects({ + Permissions: ['navigator.permissions'], + PermissionStatus: ['permissionStatus'] + }); } - - if (self.GLOBAL.isWorker()) { - idl_array.add_objects({ WorkerNavigator: ['navigator'] }); - } else { - idl_array.add_objects({ Navigator: ['navigator'] }); - } - - idl_array.add_objects({ - Permissions: ['navigator.permissions'], - PermissionStatus: ['permissionStatus'] - }); - idl_array.test(); -}, "Test IDL implementation of Permissions API"); +);
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/idlharness.window.js b/third_party/blink/web_tests/external/wpt/requestidlecallback/idlharness.window.js index 2c9f6593..69cd5a4 100644 --- a/third_party/blink/web_tests/external/wpt/requestidlecallback/idlharness.window.js +++ b/third_party/blink/web_tests/external/wpt/requestidlecallback/idlharness.window.js
@@ -1,30 +1,24 @@ // META: script=/resources/WebIDLParser.js // META: script=/resources/idlharness.js -async_test(function() { - const srcs = ['requestidlecallback', 'html', 'dom']; - Promise.all(srcs.map(i => fetch(`/interfaces/${i}.idl`).then(r => r.text()))) - .then(([idl, html, dom]) => { - var idl_array = new IdlArray(); - idl_array.add_idls(idl); - idl_array.add_dependency_idls(html); - idl_array.add_dependency_idls(dom); - idl_array.add_objects({Window: ['window']}); +// https://w3c.github.io/requestidlecallback/ - let deadline; - const execIDLTest = this.step_func_done(function() { - idl_array.add_objects({IdleDeadline: [deadline]}); - idl_array.test(); - }); +'use strict'; - if (!window.requestIdleCallback) { - execIDLTest(); - } else { - const callback = this.step_func(d => { - deadline = d; - execIDLTest(); - }); - requestIdleCallback(callback, { timeout: 100 }); - } +idl_test( + ['requestidlecallback'], + ['html', 'dom'], + async idl_array => { + idl_array.add_objects({ + IdleDeadline: ['deadline'], + Window: ['window'], }); -}, 'IdleDeadline object setup'); + + await new Promise(resolve => { + requestIdleCallback(d => { + self.deadline = d; + resolve(); + }, { timeout: 100 }); + }); + } +);
diff --git a/third_party/blink/web_tests/external/wpt/server-timing/idlharness.https.any.js b/third_party/blink/web_tests/external/wpt/server-timing/idlharness.https.any.js index 9c101e0f..ded320f0 100644 --- a/third_party/blink/web_tests/external/wpt/server-timing/idlharness.https.any.js +++ b/third_party/blink/web_tests/external/wpt/server-timing/idlharness.https.any.js
@@ -5,17 +5,12 @@ // https://w3c.github.io/server-timing/ -promise_test(async () => { - const idl = await fetch('/interfaces/server-timing.idl').then(r => r.text()); - const res = await fetch('/interfaces/resource-timing.idl').then(r => r.text()); - const perf = await fetch('/interfaces/performance-timeline.idl').then(r => r.text()); - - const idl_array = new IdlArray(); - idl_array.add_idls(idl); - idl_array.add_dependency_idls(res); - idl_array.add_dependency_idls(perf); - idl_array.add_objects({ - Performance: ['performance'], - }); - idl_array.test(); -}, 'Test server-timing IDL implementation'); +idl_test( + ['server-timing'], + ['resource-timing', 'performance-timeline'], + idl_array => { + idl_array.add_objects({ + Performance: ['performance'], + }); + } +);
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js b/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js index b9ec1b4..9be02560 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js
@@ -1,3 +1,3 @@ // AUTO-GENERATED - DO NOT EDIT. See tools/gen_version. -export const version = '84ef21bec576c9272e64e08727dbdf75a2b0e9d8'; +export const version = 'f690ac56a3291801e817433f43877132bb531d5f';
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/basic.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/basic.spec.js index bb201db..83bb026 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/basic.spec.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/basic.spec.js
@@ -22,7 +22,7 @@ }, usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT }); - const colorAttachmentView = colorAttachment.createDefaultView(); + const colorAttachmentView = colorAttachment.createView(); const encoder = t.device.createCommandEncoder({}); const pass = encoder.beginRenderPass({ colorAttachments: [{
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js index 762285d..c8a7d7f 100644 --- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js +++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js
@@ -20,7 +20,7 @@ }, usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT }); - const colorAttachmentView = colorAttachment.createDefaultView(); + const colorAttachmentView = colorAttachment.createView(); const vertexModule = t.device.createShaderModule({ code: /* GLSL(
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin-expected.txt b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin-expected.txt new file mode 100644 index 0000000..c780b570 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin-expected.txt
@@ -0,0 +1,20 @@ +Validate IndexeddbModel clearForOrigin + +Create IndexedDB in main frame +Database Length: 1 +Database Entries: + Security Origin:http://127.0.0.1:8000, Database Name:Database-main-frame +**done** + +Removing bogus security origin... +Database Length: 1 +Database Entries: + Security Origin:http://127.0.0.1:8000, Database Name:Database-main-frame +**done** + +Removing http://127.0.0.1:8000 security origin... +Database Length: 0 +Database Entries: +**done** + +
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin.js b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin.js new file mode 100644 index 0000000..6f80e6c --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin.js
@@ -0,0 +1,51 @@ +// Copyright 2019 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. + +(async function() { + TestRunner.addResult(`Validate IndexeddbModel clearForOrigin\n`); + await TestRunner.loadModule('application_test_runner'); + // Note: every test that uses a storage API must manually clean-up state from previous tests. + await ApplicationTestRunner.resetState(); + + await TestRunner.loadModule('console_test_runner'); + await TestRunner.showPanel('resources'); + + const model = TestRunner.mainTarget.model(Resources.IndexedDBModel); + const view = UI.panels.resources; + + function createIndexedDBInMainFrame(callback) { + var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id; + ApplicationTestRunner.createDatabase(mainFrameId, 'Database-main-frame', () => { + var event = model.addEventListener(Resources.IndexedDBModel.Events.DatabaseAdded, () => { + Common.EventTarget.removeEventListeners([event]); + callback(); + }); + model.refreshDatabaseNames(); + }); + } + + function dumpDatabases() { + const databases = model.databases(); + TestRunner.addResult('Database Length: ' + databases.length); + TestRunner.addResult('Database Entries:'); + for (let j = 0; j < databases.length; ++j) + TestRunner.addResult(` Security Origin:${databases[j].securityOrigin}, Database Name:${databases[j].name}`); + TestRunner.addResult('**done**\n'); + } + + TestRunner.addResult('Create IndexedDB in main frame'); + await new Promise(createIndexedDBInMainFrame); + await TestRunner.addSnifferPromise(UI.panels.resources._sidebar.indexedDBListTreeElement, '_indexedDBLoadedForTest'); + dumpDatabases(); + + TestRunner.addResult('Removing bogus security origin...'); + model.clearForOrigin('http://bogus-security-origin.com'); + dumpDatabases(); + + TestRunner.addResult('Removing http://127.0.0.1:8000 security origin...'); + model.clearForOrigin('http://127.0.0.1:8000'); + dumpDatabases(); + + TestRunner.completeTest(); +})();
diff --git a/third_party/blink/web_tests/media/picture-in-picture/picture-in-picture-service-error.html b/third_party/blink/web_tests/media/picture-in-picture/picture-in-picture-service-error.html index 2a02e74..9f4247e 100644 --- a/third_party/blink/web_tests/media/picture-in-picture/picture-in-picture-service-error.html +++ b/third_party/blink/web_tests/media/picture-in-picture/picture-in-picture-service-error.html
@@ -22,7 +22,7 @@ } async startSession(playerId, surfaceId, naturalSize, showPlayPauseButton, - showMuteButton, observer, callback) { + observer, callback) { return { session: null, size: new gfx.mojom.Size() }; } };
diff --git a/third_party/closure_compiler/externs/settings_private.js b/third_party/closure_compiler/externs/settings_private.js index fc5c38da..e2870f25 100644 --- a/third_party/closure_compiler/externs/settings_private.js +++ b/third_party/closure_compiler/externs/settings_private.js
@@ -47,6 +47,7 @@ chrome.settingsPrivate.Enforcement = { ENFORCED: 'ENFORCED', RECOMMENDED: 'RECOMMENDED', + PARENT_SUPERVISED: 'PARENT_SUPERVISED', }; /**
diff --git a/third_party/libaddressinput/OWNERS b/third_party/libaddressinput/OWNERS index b483a338..75aa61f 100644 --- a/third_party/libaddressinput/OWNERS +++ b/third_party/libaddressinput/OWNERS
@@ -1,4 +1,7 @@ -rouslan@chromium.org +battre@chromium.org +dvadym@chromium.org +kolos@chromium.org mathp@chromium.org +rouslan@chromium.org # COMPONENT: UI>Browser>Autofill
diff --git a/third_party/libipp/BUILD.gn b/third_party/libipp/BUILD.gn new file mode 100644 index 0000000..3653f9c --- /dev/null +++ b/third_party/libipp/BUILD.gn
@@ -0,0 +1,29 @@ +# Copyright 2019 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +static_library("libipp") { + include_dirs = [ "." ] + sources = [ + "libipp/ipp.h", + "libipp/ipp_attribute.cc", + "libipp/ipp_attribute.h", + "libipp/ipp_base.cc", + "libipp/ipp_base.h", + "libipp/ipp_collections.cc", + "libipp/ipp_collections.h", + "libipp/ipp_encoding.h", + "libipp/ipp_enums.cc", + "libipp/ipp_enums.h", + "libipp/ipp_export.h", + "libipp/ipp_frame.h", + "libipp/ipp_frame_builder.cc", + "libipp/ipp_frame_builder.h", + "libipp/ipp_operations.cc", + "libipp/ipp_operations.h", + "libipp/ipp_package.cc", + "libipp/ipp_package.h", + "libipp/ipp_parser.cc", + "libipp/ipp_parser.h", + ] +}
diff --git a/third_party/libipp/LICENSE b/third_party/libipp/LICENSE new file mode 100644 index 0000000..5448446 --- /dev/null +++ b/third_party/libipp/LICENSE
@@ -0,0 +1,27 @@ +// Copyright 2019 The Chromium OS Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/libipp/OWNERS b/third_party/libipp/OWNERS new file mode 100644 index 0000000..4529fb66 --- /dev/null +++ b/third_party/libipp/OWNERS
@@ -0,0 +1,2 @@ +pawliczek@chromium.org +skau@chromium.org
diff --git a/third_party/libipp/README.chromium b/third_party/libipp/README.chromium new file mode 100644 index 0000000..f68030f8 --- /dev/null +++ b/third_party/libipp/README.chromium
@@ -0,0 +1,17 @@ +Name: libipp +URL: https://chromium.googlesource.com/chromiumos/platform2/libipp +Version: 6c45a4f3a05cb5dd700414fe4d94cf685159d3ce +License: BSD +License File: LICENSE +Security Critical: yes + +Description: +ChromeOS library for bulding/parsing IPP frames. + +Modifications: +- None + +To import a new snapshot of libipp: +- Checkout the latest version: git checkout 6c45a4f3a05cb5dd700414fe4d94cf685159d3ce +- Change the chromium/src/DEPS entry to the newly checked out commit. +- Update this README to reflect the new version number.
diff --git a/third_party/libphonenumber/OWNERS b/third_party/libphonenumber/OWNERS index ce847508..75aa61f 100644 --- a/third_party/libphonenumber/OWNERS +++ b/third_party/libphonenumber/OWNERS
@@ -1,3 +1,6 @@ +battre@chromium.org +dvadym@chromium.org +kolos@chromium.org mathp@chromium.org rouslan@chromium.org
diff --git a/tools/flags/generate_expired_list.py b/tools/flags/generate_expired_list.py new file mode 100755 index 0000000..da5b65c --- /dev/null +++ b/tools/flags/generate_expired_list.py
@@ -0,0 +1,125 @@ +#!/usr/bin/env python +# Copyright 2019 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. + + +"""Generates the list of expired flags as a C++ source file. + +This program generates a data structure representing the set of flags that +expired before or as of the current Chromium milestone. Specifically, it reads +the flag metadata JSON file and emits a structure mapping flag internal names to +expiration milestones. This data structure is then linked into the built +Chromium, to be used to decide whether to show or hide a given flag in the flags +UI. + +This program can be run with no arguments to run its own unit tests. +""" + + +import list_flags +import os +import sys + + +ROOT_PATH = os.path.join(os.path.dirname(__file__), '..', '..') + + +def get_chromium_version(): + """Parses the Chromium version out of //chrome/VERSION.""" + with open(os.path.join(ROOT_PATH, 'chrome', 'VERSION')) as f: + for line in f.readlines(): + key, value = line.strip().split('=') + if key == 'MAJOR': + return value + return None + + +def gen_file_header(prog_name, meta_name): + """Returns the header for the generated expiry list file. + + The generated header contains at least: + * A copyright message on the first line + * A reference to this program (prog_name) + * A reference to the input metadata file + >>> 'The Chromium Authors' in gen_file_header('foo', 'bar') + True + >>> '/progname' in gen_file_header('/progname', '/dataname') + True + >>> '/dataname' in gen_file_header('/progname', '/dataname') + True + """ + return """// Copyright 2019 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. + +// This is a generated file. Do not edit it! It was generated by: +// {prog_name} +// and it was generated from: +// {meta_name} + +#include "chrome/browser/expired_flags_list.h" + +namespace flags {{ +const ExpiredFlag kExpiredFlags[] = {{ +""".format(prog_name=prog_name, meta_name=meta_name) + + +def gen_file_footer(): + return """ + {nullptr, 0}, +}; + +} // namespace flags""" + + +def gen_file_body(flags, mstone): + """Generates the body of the flag expiration list. + + Flags appear in the list only if: + * Their expiration mstone is not -1 + * Either the chrome version is unknown OR + * Their expiration mstone is <= the chrome version + + >>> flags = [ { 'name': 'foo', 'expiry_milestone': 1 } ] + >>> flags.append({ 'name': 'bar', 'expiry_milestone': 2 }) + >>> flags.append({ 'name': 'baz', 'expiry_milestone': -1 }) + >>> gen_file_body(flags, 1) + ' {"foo", 1},' + >>> gen_file_body(flags, 2) + ' {"foo", 1},\\n {"bar", 2},' + >>> gen_file_body(flags, None) + ' {"foo", 1},\\n {"bar", 2},' + """ + if mstone != None: + flags = list_flags.keep_expired_by(flags, mstone) + output = [] + for f in flags: + if f['expiry_milestone'] != -1: + name, expiry = f['name'], f['expiry_milestone'] + output.append(' {"' + name + '", ' + str(expiry) + '},') + return '\n'.join(output) + + +def gen_expiry_file(program_name, metadata_name): + output = gen_file_header(program_name, metadata_name) + output += gen_file_body(list_flags.load_metadata(), get_chromium_version()) + output += gen_file_footer() + return output + + +def main(): + import doctest + doctest.testmod() + + if len(sys.argv) < 3: + print '{}: only ran tests'.format(sys.argv[0]) + return + + output = gen_expiry_file(sys.argv[0], sys.argv[1]) + with open(sys.argv[2], 'w') as f: + f.write(output) + + +if __name__ == '__main__': + main()
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index 04df1f8a..8f26bd5 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -1100,6 +1100,7 @@ # TODO(https://crbug.com/912946): Remove this if statement. if (f == 'angledata/gl_cts/' or # http://anglebug.com/3827 (is_msan and f == 'instrumented_libraries_prebuilt/') or + f == 'mr_extension/' or # https://crbug.com/997947 f == 'locales/' or f.startswith('nacl_test_data/') or f.startswith('ppapi_nacl_tests_libs/') or
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 1282da44..62a8cdb 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -35200,6 +35200,7 @@ <int value="-996673716" label="enable-web-app-frame"/> <int value="-994558985" label="EnableNotificationIndicator:disabled"/> <int value="-994088375" label="VrBrowsingExperimentalRendering:enabled"/> + <int value="-994044484" label="TemporaryUnexpireFlagsM76:disabled"/> <int value="-993476089" label="AutoScreenBrightness:disabled"/> <int value="-992785453" label="ExplicitLanguageAsk:disabled"/> <int value="-991253797" @@ -35852,6 +35853,7 @@ <int value="-79327236" label="ModeSpecificPowerButton:enabled"/> <int value="-78035185" label="custom_summary"/> <int value="-77872983" label="BookmarkAppsMac:disabled"/> + <int value="-76953963" label="CloseTabSuggestionsStale:enabled"/> <int value="-76631048" label="disable-offline-auto-reload-visible-only"/> <int value="-76445689" label="WasmCodeCache:enabled"/> <int value="-75418012" label="ContextualSuggestionsOptOut:disabled"/> @@ -36649,6 +36651,7 @@ <int value="1060319397" label="enable-data-reduction-proxy-carrier-test"/> <int value="1062357243" label="remember-cert-error-decisions"/> <int value="1064288458" label="OfflineRecentPages:enabled"/> + <int value="1065216170" label="CloseTabSuggestionsStale:disabled"/> <int value="1067618884" label="enable-experimental-input-view-features"/> <int value="1067990299" label="enable-ui-devtools"/> <int value="1069325321" label="CrostiniGpuSupport:enabled"/> @@ -37182,6 +37185,7 @@ label="ContextualSuggestionsIPHReverseScroll:disabled"/> <int value="1803465156" label="enable-zero-suggest-most-visited"/> <int value="1803470125" label="SyncUSSSessions:enabled"/> + <int value="1803914892" label="TemporaryUnexpireFlagsM76:enabled"/> <int value="1807374811" label="CCTModuleCache:enabled"/> <int value="1809940714" label="SpeculativeLaunchServiceWorker:disabled"/> <int value="1810258949" label="DisplayLocking:enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 16b978d4..c64180bd 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -1576,6 +1576,17 @@ </summary> </histogram> +<histogram name="Android.BackgroundTaskScheduler.ExactTaskCreated" + enum="BackgroundTaskId" expires_after="2020-01-31"> + <owner>ioanastefan@chromium.org</owner> + <owner>nator@chromium.org</owner> + <owner>knollr@chromium.org</owner> + <summary> + Records that an exact task has been created. Recorded when the task is + scheduled. + </summary> +</histogram> + <histogram name="Android.BackgroundTaskScheduler.MigrationToProto" enum="BackgroundTaskId" expires_after="2019-11-30"> <owner>ioanastefan@chromium.org</owner> @@ -128808,21 +128819,25 @@ </histogram> <histogram name="Signin.AndroidGetAccountIdsTime" units="ms" - expires_after="2020-02-16"> + expires_after="M82"> + <owner>alexilin@chromium.org</owner> <owner>bsazonov@chromium.org</owner> <summary> The time it takes to retrieve Gaia ids for all accounts from GoogleAuthUtil. </summary> </histogram> -<histogram name="Signin.AndroidGetAccountsTime" units="ms"> - <owner>nyquist@chromium.org</owner> +<histogram name="Signin.AndroidGetAccountsTime" units="ms" expires_after="M82"> + <owner>alexilin@chromium.org</owner> + <owner>bsazonov@chromium.org</owner> <summary> The time it takes to retrieve the list of accounts from the system. </summary> </histogram> -<histogram name="Signin.AndroidGetAccountsTimeUiThread" units="ms"> +<histogram name="Signin.AndroidGetAccountsTimeUiThread" units="ms" + expires_after="M82"> + <owner>alexilin@chromium.org</owner> <owner>bsazonov@chromium.org</owner> <summary> The time it takes to retrieve the list of accounts from the system on the UI
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc index 200ee16..93b6823 100644 --- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc +++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
@@ -197,7 +197,8 @@ // Get list of files/folders to process. std::vector<std::string> file_paths; - GenerateFilesListForClangTool(path_filters, filter_files_based_on_heuristics, + GenerateFilesListForClangTool(backend, path_filters, + filter_files_based_on_heuristics, use_compile_commands, &file_paths); if (file_paths.empty()) return true; @@ -334,27 +335,33 @@ } void TrafficAnnotationAuditor::GenerateFilesListForClangTool( + ExtractorBackend backend, const std::vector<std::string>& path_filters, bool filter_files_based_on_heuristics, bool use_compile_commands, std::vector<std::string>* file_paths) { + TrafficAnnotationFileFilter filter; + // If |use_compile_commands| is requested or // |filter_files_based_on_heuristics| is false, we pass all given file paths // to the running script and the files in the safe list will be later removed // from the results. if (!filter_files_based_on_heuristics || use_compile_commands) { - // If no path filter is specified, return current location. The clang tool - // will be run from the repository 'src' folder and hence this will point to - // repository root. - if (path_filters.empty()) + if (backend == ExtractorBackend::PYTHON_SCRIPT) { + // With python_script, simply run on the whole directory. + filter.GetFilesFromGit(absolute_source_path_); + *file_paths = filter.git_files(); + } else if (path_filters.empty()) { + // If no path filter is specified, return current location. The clang tool + // will be run from the repository 'src' folder and hence this will point + // to repository root. file_paths->push_back("./"); - else + } else { *file_paths = path_filters; + } return; } - TrafficAnnotationFileFilter filter; - // If no path filter is provided, get all relevant files, except the safe // listed ones. if (path_filters.empty()) {
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h index 3c32a52..323f9d6 100644 --- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h +++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
@@ -199,6 +199,7 @@ // Generates files list to Run clang tool on. Please refer to RunExtractor // function's comment. void GenerateFilesListForClangTool( + ExtractorBackend backend, const std::vector<std::string>& path_filters, bool filter_files_based_on_heuristics, bool use_compile_commands,
diff --git a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 index 74681b9..bffaadb 100644 --- a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 +++ b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
@@ -1 +1 @@ -62dbe9751c9d8d03810f9928e29859e5af43db8d \ No newline at end of file +e3a801da7edfd02cf050f233738e44a8f9e526d2 \ No newline at end of file
diff --git a/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1 b/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1 index bde6d84f..92f1f46 100644 --- a/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1 +++ b/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
@@ -1 +1 @@ -135da9329dc7bfe8e8056ed3976a704c777d49f3 \ No newline at end of file +2390166409ac2d4a87539ceefc99f56a6a68b105 \ No newline at end of file
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index a0e8812d..e1284e9 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -5897,7 +5897,7 @@ return UIA_PaneControlTypeId; case ax::mojom::Role::kArticle: - return UIA_DocumentControlTypeId; + return UIA_GroupControlTypeId; case ax::mojom::Role::kAudio: return UIA_GroupControlTypeId;
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc index bd957f94..a1f63cef 100644 --- a/ui/accessibility/platform/test_ax_node_wrapper.cc +++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -578,6 +578,9 @@ base::string16 TestAXNodeWrapper::GetLocalizedStringForRoleDescription() const { const AXNodeData& data = GetData(); switch (data.role) { + case ax::mojom::Role::kArticle: + return base::ASCIIToUTF16("article"); + case ax::mojom::Role::kAudio: return base::ASCIIToUTF16("audio"); @@ -603,6 +606,9 @@ case ax::mojom::Role::kDetails: return base::ASCIIToUTF16("details"); + case ax::mojom::Role::kFigure: + return base::ASCIIToUTF16("figure"); + case ax::mojom::Role::kMeter: return base::ASCIIToUTF16("meter");
diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc index 1fe00525..b3887da 100644 --- a/ui/aura/window_event_dispatcher.cc +++ b/ui/aura/window_event_dispatcher.cc
@@ -20,7 +20,6 @@ #include "ui/aura/client/screen_position_client.h" #include "ui/aura/env.h" #include "ui/aura/env_input_state_controller.h" -#include "ui/aura/window.h" #include "ui/aura/window_delegate.h" #include "ui/aura/window_event_dispatcher_observer.h" #include "ui/aura/window_targeter.h"
diff --git a/ui/aura/window_event_dispatcher.h b/ui/aura/window_event_dispatcher.h index 680ff3e..f1a1bcad5 100644 --- a/ui/aura/window_event_dispatcher.h +++ b/ui/aura/window_event_dispatcher.h
@@ -18,6 +18,7 @@ #include "ui/aura/aura_export.h" #include "ui/aura/client/capture_delegate.h" #include "ui/aura/env_observer.h" +#include "ui/aura/window.h" #include "ui/aura/window_observer.h" #include "ui/base/cursor/cursor.h" #include "ui/events/event_constants.h"
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc index 02579ea..9da2d35 100644 --- a/ui/compositor/layer.cc +++ b/ui/compositor/layer.cc
@@ -230,6 +230,8 @@ cc_layer_->RemoveFromParent(); if (transfer_release_callback_) transfer_release_callback_->Run(gpu::SyncToken(), false); + + ResetSubtreeReflectedLayer(); } std::unique_ptr<Layer> Layer::Clone() const { @@ -738,12 +740,7 @@ animator_->SwitchToLayer(new_layer); } - if (subtree_reflected_layer_) { - size_t result = - subtree_reflected_layer_->subtree_reflecting_layers_.erase(this); - DCHECK_EQ(1u, result); - subtree_reflected_layer_ = nullptr; - } + ResetSubtreeReflectedLayer(); if (texture_layer_.get()) texture_layer_->ClearClient(); @@ -1632,4 +1629,14 @@ SetBounds(new_bounds); } +void Layer::ResetSubtreeReflectedLayer() { + if (!subtree_reflected_layer_) + return; + + size_t result = + subtree_reflected_layer_->subtree_reflecting_layers_.erase(this); + DCHECK_EQ(1u, result); + subtree_reflected_layer_ = nullptr; +} + } // namespace ui
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h index f40db7c1..2e77a40e0 100644 --- a/ui/compositor/layer.h +++ b/ui/compositor/layer.h
@@ -603,6 +603,10 @@ // Changes the size of |this| to match that of |layer|. void MatchLayerSize(const Layer* layer); + // Resets |subtree_reflected_layer_| and updates the reflected layer's + // |subtree_reflecting_layers_| list accordingly. + void ResetSubtreeReflectedLayer(); + const LayerType type_; Compositor* compositor_;
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc index 87b1a6b3..fda43bb 100644 --- a/ui/compositor/layer_unittest.cc +++ b/ui/compositor/layer_unittest.cc
@@ -1594,6 +1594,12 @@ reflected_layer->SetBounds(new_reflected_bounds); EXPECT_EQ(reflecting_bounds.origin(), reflecting_layer->bounds().origin()); EXPECT_EQ(new_reflected_bounds.size(), reflecting_layer->bounds().size()); + + // No crashes on reflected layer bounds change after the reflecting layer is + // released. + reflecting_layer = nullptr; + reflected_layer->SetBounds(reflected_bounds); + EXPECT_EQ(reflected_bounds, reflected_layer->bounds()); } void ExpectRgba(int x, int y, SkColor expected_color, SkColor actual_color) {
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd index 5dfb97992..fbcc0fab 100644 --- a/ui/strings/ui_strings.grd +++ b/ui/strings/ui_strings.grd
@@ -988,8 +988,8 @@ <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_FAILED_MESSAGE" desc="The label to be shown on the dialog when user click on a phone number, if sending it to a device failed."> Check your phone's connection and try again </message> - <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_SEND_SUCCESS" desc="The label to be shown next to the omnibox icon after a phone number got sent to a users device."> - Sent to device + <message name="IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL" desc="The label to be shown next to the omnibox icon when the message is being sent to the other device."> + Sending... </message> </messages> </release>
diff --git a/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL.png.sha1 b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL.png.sha1 new file mode 100644 index 0000000..c9ca773 --- /dev/null +++ b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL.png.sha1
@@ -0,0 +1 @@ +be4376302ced60a07f2e318dbd8fa5f0a70cb969 \ No newline at end of file
diff --git a/ui/views/animation/animation_delegate_views.cc b/ui/views/animation/animation_delegate_views.cc index 660e42f..9bd14c74 100644 --- a/ui/views/animation/animation_delegate_views.cc +++ b/ui/views/animation/animation_delegate_views.cc
@@ -6,7 +6,6 @@ #include "ui/gfx/animation/animation_container.h" #include "ui/views/animation/compositor_animation_runner.h" -#include "ui/views/view.h" #include "ui/views/widget/widget.h" namespace views {
diff --git a/ui/views/animation/animation_delegate_views.h b/ui/views/animation/animation_delegate_views.h index ee025be..637b718f 100644 --- a/ui/views/animation/animation_delegate_views.h +++ b/ui/views/animation/animation_delegate_views.h
@@ -10,13 +10,12 @@ #include "base/scoped_observer.h" #include "ui/gfx/animation/animation_container_observer.h" #include "ui/gfx/animation/animation_delegate.h" +#include "ui/views/view.h" #include "ui/views/view_observer.h" #include "ui/views/views_export.h" namespace views { -class View; - // Provides default implementaton to adapt CompositorAnimationRunner for // Animation. Falls back to the default animation runner when |view| is nullptr. class VIEWS_EXPORT AnimationDelegateViews @@ -52,7 +51,7 @@ View* view_; gfx::AnimationContainer* container_ = nullptr; - ScopedObserver<View, AnimationDelegateViews> scoped_observer_{this}; + ScopedObserver<View, ViewObserver> scoped_observer_{this}; }; } // namespace views
diff --git a/ui/views/animation/compositor_animation_runner.cc b/ui/views/animation/compositor_animation_runner.cc index e5abea4..07aa4e4 100644 --- a/ui/views/animation/compositor_animation_runner.cc +++ b/ui/views/animation/compositor_animation_runner.cc
@@ -4,8 +4,6 @@ #include "ui/views/animation/compositor_animation_runner.h" -#include "ui/compositor/compositor.h" - namespace views { ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/animation/compositor_animation_runner.h b/ui/views/animation/compositor_animation_runner.h index 58a9ab7..b1da6213 100644 --- a/ui/views/animation/compositor_animation_runner.h +++ b/ui/views/animation/compositor_animation_runner.h
@@ -7,14 +7,11 @@ #include "base/scoped_observer.h" #include "base/time/time.h" +#include "ui/compositor/compositor.h" #include "ui/compositor/compositor_animation_observer.h" #include "ui/compositor/compositor_observer.h" #include "ui/gfx/animation/animation_container.h" -namespace ui { -class Compositor; -} // namespace ui - namespace views { // An animation runner based on ui::Compositor. @@ -51,7 +48,8 @@ private: CompositorAnimationRunner* runner_; - ScopedObserver<ui::Compositor, CompositorChecker> scoped_observer_{this}; + ScopedObserver<ui::Compositor, ui::CompositorObserver> scoped_observer_{ + this}; }; // When |compositor_| is nullptr, it means compositor has been shut down.
diff --git a/ui/views/bubble/tooltip_icon.cc b/ui/views/bubble/tooltip_icon.cc index 289e921..e007660 100644 --- a/ui/views/bubble/tooltip_icon.cc +++ b/ui/views/bubble/tooltip_icon.cc
@@ -19,8 +19,7 @@ tooltip_icon_size_(tooltip_icon_size), mouse_inside_(false), bubble_(nullptr), - preferred_width_(0), - observer_(this) { + preferred_width_(0) { SetDrawAsHovered(false); }
diff --git a/ui/views/bubble/tooltip_icon.h b/ui/views/bubble/tooltip_icon.h index cb10e59..073241b 100644 --- a/ui/views/bubble/tooltip_icon.h +++ b/ui/views/bubble/tooltip_icon.h
@@ -14,6 +14,7 @@ #include "ui/views/bubble/bubble_border.h" #include "ui/views/controls/image_view.h" #include "ui/views/mouse_watcher.h" +#include "ui/views/widget/widget.h" #include "ui/views/widget/widget_observer.h" namespace views { @@ -89,7 +90,7 @@ // A watcher that keeps |bubble_| open if the user's mouse enters it. std::unique_ptr<MouseWatcher> mouse_watcher_; - ScopedObserver<Widget, TooltipIcon> observer_; + ScopedObserver<Widget, WidgetObserver> observer_{this}; DISALLOW_COPY_AND_ASSIGN(TooltipIcon); };
diff --git a/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn b/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn index 30fde56..0d6271b 100644 --- a/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn +++ b/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn
@@ -43,7 +43,7 @@ deps = [ ":cr_network_list_types", ":cr_onc_types", - "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior", + "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior_mojo", "//ui/webui/resources/js:assert", ] }
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html b/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html index 9d52d4d..d7c76b7 100644 --- a/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html +++ b/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html
@@ -6,7 +6,7 @@ <link rel="import" href="../../cr_icon_button/cr_icon_button.html"> <link rel="import" href="../../icons.html"> <link rel="import" href="../../policy/cr_policy_indicator.html"> -<link rel="import" href="../../policy/cr_policy_network_behavior.html"> +<link rel="import" href="../../policy/cr_policy_network_behavior_mojo.html"> <link rel="import" href="../../shared_style_css.html"> <link rel="import" href="../../shared_vars_css.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> @@ -75,8 +75,8 @@ [[getNetworkStateText_(networkState)]] </div> </div> - <template is="dom-if" if="[[isPolicySourceMojo(networkState.source)]]"> - <cr-policy-indicator indicator-type="[[getIndicatorTypeForSourceMojo( + <template is="dom-if" if="[[isPolicySource(networkState.source)]]"> + <cr-policy-indicator indicator-type="[[getIndicatorTypeForSource( networkState.source)]]"> </cr-policy-indicator> </template>
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js b/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js index d3425683..a329cfe 100644 --- a/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js +++ b/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js
@@ -10,6 +10,10 @@ Polymer({ is: 'cr-network-list-item', + behaviors: [ + CrPolicyNetworkBehaviorMojo, + ], + properties: { /** @type {!CrNetworkList.CrNetworkListItemType|undefined} */ item: { @@ -65,8 +69,6 @@ showTechnologyBadge: {type: Boolean, value: true}, }, - behaviors: [CrPolicyNetworkBehavior], - /** @override */ attached: function() { this.listen(this, 'keydown', 'onKeydown_');
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js b/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js index 68b1040..aff8824 100644 --- a/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js +++ b/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js
@@ -108,17 +108,6 @@ }, /** - * @param {chromeos.networkConfig.mojom.OncSource} source - * @return {boolean} - * @protected - */ - isPolicySourceMojo: function(source) { - return !!source && - (source == chromeos.networkConfig.mojom.OncSource.kDevicePolicy || - source == chromeos.networkConfig.mojom.OncSource.kUserPolicy); - }, - - /** * @param {string} source * @return {!CrPolicyIndicatorType} * @private @@ -134,21 +123,6 @@ }, /** - * @param {chromeos.networkConfig.mojom.OncSource} source - * @return {!CrPolicyIndicatorType} - * @private - */ - getIndicatorTypeForSourceMojo: function(source) { - if (source == chromeos.networkConfig.mojom.OncSource.kDevicePolicy) { - return CrPolicyIndicatorType.DEVICE_POLICY; - } - if (source == chromeos.networkConfig.mojom.OncSource.kUserPolicy) { - return CrPolicyIndicatorType.USER_POLICY; - } - return CrPolicyIndicatorType.NONE; - }, - - /** * @param {Object} dict A managed ONC dictionary. * @param {string} path A path to a setting inside |dict|. * @return {!CrOnc.ManagedProperty|undefined} The value of the setting at
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html b/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html index 37120ce..52a50e3 100644 --- a/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html +++ b/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html
@@ -3,11 +3,6 @@ <link rel="import" href="../hidden_style_css.html"> <link rel="import" href="cr_policy_indicator_behavior.html"> <link rel="import" href="cr_policy_network_behavior.html"> -<!-- Currently cr_policy_network_behavior_mojo.html is included only for testing - in cr_policy_network_behavior_mojo_tests.js which requires the behavior to - be loaded from an html file that the browser knows about. - TODO(853953): Convert this class to use the mojo API. --> -<link rel="import" href="cr_policy_network_behavior_mojo.html"> <link rel="import" href="cr_tooltip_icon.html"> <dom-module id="cr-policy-network-indicator">
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js b/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js index 6362e1b4..563e77a4 100644 --- a/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js +++ b/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js
@@ -67,6 +67,9 @@ return CrPolicyIndicatorType.CHILD_RESTRICTION; } } + if (enforcement == chrome.settingsPrivate.Enforcement.PARENT_SUPERVISED) { + return CrPolicyIndicatorType.PARENT; + } return CrPolicyIndicatorType.NONE; },