diff --git a/BUILD.gn b/BUILD.gn index bf2ddc9..0e7a624 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -389,10 +389,6 @@ ] } - if (target_cpu != "x64") { - deps += [ "//content/shell/android:chromium_linker_test_apk" ] - } - if (enable_chrome_android_internal) { deps += [ "//clank" ] }
diff --git a/DEPS b/DEPS index 02f518b3..7461b416f 100644 --- a/DEPS +++ b/DEPS
@@ -175,11 +175,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': '0340292972b9719ac8eec5ddccff2805b9045d42', + 'skia_revision': '6dc0f63a509cc111cbda2a419cc835bd65272bb0', # 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': '576a8e97c96ee49267829f4c6825b257cf533f77', + 'v8_revision': '83b2817d8edb5b18f82a57b2500f76e4b6e43849', # 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. @@ -187,11 +187,11 @@ # 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': '45c5398037c4daefd01ef466292497790ba28ef0', + 'angle_revision': 'd0748eb038be66dfd05c05773d1edbfd3bdacbc8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '16ae92a4ee5212883f1dbeefd1a91f924b2c2548', + 'swiftshader_revision': 'ce25c2d434cfba5c7edee5b82078e033bc0057f2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -238,7 +238,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'e4aabc8bab65e599245a36962a229c9dec2c4b5d', + 'catapult_revision': '7004f998c7ba0e88c27d6f294666dd67b0916ec8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -246,7 +246,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': 'af976e22c803c07f578a59826583ab72d5faa246', + 'devtools_frontend_revision': '6a14c8da7c4d00e6631b01aef693561d591b24d7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -532,7 +532,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '8a6d4f9ab70a581253c8c2fb89ba6e076b71431a', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'ecb6de8a5a229721f761f13056c584c2b9208b6c', 'condition': 'checkout_ios', }, @@ -874,7 +874,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8cf4a76817cbc62ad4e47a230978355a79840009', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'c7796cf40d5ee7694c8d8abe91d4ee1023444bd8', 'condition': 'checkout_linux', }, @@ -1250,7 +1250,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'ccdbaf215f0c8ff228c7ddf615fb50efe9ed6f04', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c095a02a0ee049448900116fea85bd35d4cf30f6', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1454,7 +1454,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'ec18cc3262922e7dcdbe70243c6f40606f979144', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '59f3b71c04deb301c989d8f316424d01dd91d2c5', + Var('webrtc_git') + '/src.git' + '@' + '4d3f93f348136b6cbad827124be4cedf5794aab3', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1529,7 +1529,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1422f8e60e7b0e0b4618f4b48c7919bcdf11d456', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6ad2153566cc1e9270d681c2a621efd9537ba178', 'condition': 'checkout_src_internal', },
diff --git a/ash/home_screen/home_launcher_gesture_handler.h b/ash/home_screen/home_launcher_gesture_handler.h index 9bbae69..bcc0da1 100644 --- a/ash/home_screen/home_launcher_gesture_handler.h +++ b/ash/home_screen/home_launcher_gesture_handler.h
@@ -95,6 +95,11 @@ Mode mode() const { return mode_; } + SwipeHomeToOverviewController* + swipe_home_to_overview_controller_for_testing() { + return swipe_home_to_overview_controller_.get(); + } + private: class ScopedWindowModifier;
diff --git a/ash/shelf/contextual_nudge.cc b/ash/shelf/contextual_nudge.cc index 6bbd8f6..a989145 100644 --- a/ash/shelf/contextual_nudge.cc +++ b/ash/shelf/contextual_nudge.cc
@@ -6,6 +6,7 @@ #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/shelf/shelf.h" #include "ash/system/tray/tray_constants.h" #include "ash/wm/collision_detection/collision_detection_utils.h" #include "ui/aura/window.h" @@ -41,15 +42,17 @@ Position position, const gfx::Insets& margins, const base::string16& text, - SkColor text_color) + SkColor text_color, + const base::RepeatingClosure& tap_callback) : views::BubbleDialogDelegateView(anchor, GetArrowForPosition(position), - views::BubbleBorder::NO_ASSETS) { + views::BubbleBorder::NO_ASSETS), + tap_callback_(tap_callback) { set_color(SK_ColorTRANSPARENT); set_margins(margins); set_close_on_deactivate(false); + set_accept_events(!tap_callback.is_null()); SetCanActivate(false); - set_accept_events(false); set_adjust_if_offscreen(false); set_shadow(views::BubbleBorder::NO_ASSETS); DialogDelegate::set_buttons(ui::DIALOG_BUTTON_NONE); @@ -94,4 +97,26 @@ return ui::LAYER_NOT_DRAWN; } +void ContextualNudge::OnGestureEvent(ui::GestureEvent* event) { + if (event->type() == ui::ET_GESTURE_TAP && tap_callback_) { + event->StopPropagation(); + tap_callback_.Run(); + return; + } + + // Pass on non tap events to the shelf (so it can handle swipe gestures that + // start on top of the nudge). Convert event to screen coordinates, as this is + // what Shelf::ProcessGestureEvent() expects. + ui::GestureEvent event_in_screen(*event); + gfx::Point location_in_screen(event->location()); + View::ConvertPointToScreen(this, &location_in_screen); + event_in_screen.set_location(location_in_screen); + + Shelf* shelf = Shelf::ForWindow(GetWidget()->GetNativeWindow()); + if (shelf->ProcessGestureEvent(event_in_screen)) + event->StopPropagation(); + else + views::BubbleDialogDelegateView::OnGestureEvent(event); +} + } // namespace ash
diff --git a/ash/shelf/contextual_nudge.h b/ash/shelf/contextual_nudge.h index ce7fbe98..595a32a 100644 --- a/ash/shelf/contextual_nudge.h +++ b/ash/shelf/contextual_nudge.h
@@ -6,6 +6,7 @@ #define ASH_SHELF_CONTEXTUAL_NUDGE_H_ #include "ash/ash_export.h" +#include "base/callback.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/controls/label.h" @@ -31,12 +32,14 @@ // |margins| - The margins added to the nudge bubble. // |text| - The nudge text. // |text_color| - The nudge text label foreground color. + // |tap_callback| - If set, the callback called when the user taps the nuge. ContextualNudge(views::View* anchor, aura::Window* parent_window, Position position, const gfx::Insets& margins, const base::string16& text, - SkColor text_color); + SkColor text_color, + const base::RepeatingClosure& tap_callback); ~ContextualNudge() override; ContextualNudge(const ContextualNudge&) = delete; @@ -51,8 +54,11 @@ // BubbleDialogDelegateView: gfx::Size CalculatePreferredSize() const override; ui::LayerType GetLayerType() const override; + void OnGestureEvent(ui::GestureEvent* event) override; private: + base::RepeatingClosure tap_callback_; + views::Label* label_; };
diff --git a/ash/shelf/contextual_tooltip.cc b/ash/shelf/contextual_tooltip.cc index 22f0c47..89a465d 100644 --- a/ash/shelf/contextual_tooltip.cc +++ b/ash/shelf/contextual_tooltip.cc
@@ -90,8 +90,12 @@ if (!features::AreContextualNudgesEnabled()) return false; - if (GetSuccessCount(prefs, type) >= kSuccessLimit) + const int success_count = GetSuccessCount(prefs, type); + if (success_count >= kSuccessLimit || + (type == TooltipType::kHomeToOverview && + success_count >= kSuccessLimitHomeToOverview)) { return false; + } const int shown_count = GetShownCount(prefs, type); if (shown_count >= kNotificationLimit)
diff --git a/ash/shelf/contextual_tooltip.h b/ash/shelf/contextual_tooltip.h index 4de0c6e..7066f534 100644 --- a/ash/shelf/contextual_tooltip.h +++ b/ash/shelf/contextual_tooltip.h
@@ -25,6 +25,7 @@ // hasn't performed the gesture |kSuccessLimit| times successfully. constexpr int kNotificationLimit = 3; constexpr int kSuccessLimit = 7; +constexpr int kSuccessLimitHomeToOverview = 3; // Minimum time between showing contextual nudges to the user. constexpr base::TimeDelta kMinInterval = base::TimeDelta::FromDays(1);
diff --git a/ash/shelf/drag_handle.cc b/ash/shelf/drag_handle.cc index 4bfa304..4ff6a9c9 100644 --- a/ash/shelf/drag_handle.cc +++ b/ash/shelf/drag_handle.cc
@@ -177,7 +177,8 @@ gfx::Insets(), l10n_util::GetStringUTF16(IDS_ASH_DRAG_HANDLE_NUDGE), AshColorProvider::Get()->GetContentLayerColor( AshColorProvider::ContentLayerType::kTextPrimary, - AshColorProvider::AshColorMode::kDark)); + AshColorProvider::AshColorMode::kDark), + base::RepeatingClosure()); drag_handle_nudge_->GetWidget()->Show(); drag_handle_nudge_->label()->layer()->SetOpacity(0.0f);
diff --git a/ash/shelf/home_to_overview_nudge_controller.cc b/ash/shelf/home_to_overview_nudge_controller.cc index d0690d9..e77d1d0 100644 --- a/ash/shelf/home_to_overview_nudge_controller.cc +++ b/ash/shelf/home_to_overview_nudge_controller.cc
@@ -48,7 +48,7 @@ // The baseline vertical offset from default kShown state bounds added to // hotseat position when the nudge is shown - this is the offset that the // hotseat will have once show throb animation completes. -constexpr int kHotseatBaselineNudgeOffset = -20; +constexpr int kHotseatBaselineNudgeOffset = -22; // The number of times the nudge should be moved up and down when the nudge is // shown. @@ -167,7 +167,9 @@ l10n_util::GetStringUTF16(IDS_ASH_HOME_TO_OVERVIEW_CONTEXTUAL_NUDGE), AshColorProvider::Get()->GetContentLayerColor( AshColorProvider::ContentLayerType::kTextPrimary, - AshColorProvider::AshColorMode::kDark)); + AshColorProvider::AshColorMode::kDark), + base::BindRepeating(&HomeToOverviewNudgeController::HandleNudgeTap, + weak_factory_.GetWeakPtr())); UpdateNudgeAnchorBounds(); @@ -291,6 +293,9 @@ widget_observer_.RemoveAll(); nudge_ = nullptr; + + // Invalidated nudge tap handler callbacks. + weak_factory_.InvalidateWeakPtrs(); } void HomeToOverviewNudgeController::UpdateNudgeAnchorBounds() { @@ -307,4 +312,8 @@ gfx::Size(shelf_bounds.width(), hotseat_bounds.height()))); } +void HomeToOverviewNudgeController::HandleNudgeTap() { + HideNudge(); +} + } // namespace ash
diff --git a/ash/shelf/home_to_overview_nudge_controller.h b/ash/shelf/home_to_overview_nudge_controller.h index af7367a24..a1ce4e91 100644 --- a/ash/shelf/home_to_overview_nudge_controller.h +++ b/ash/shelf/home_to_overview_nudge_controller.h
@@ -8,6 +8,7 @@ #include <memory> #include "ash/ash_export.h" +#include "base/memory/weak_ptr.h" #include "base/scoped_observer.h" #include "base/timer/timer.h" #include "ui/views/widget/widget.h" @@ -58,6 +59,9 @@ // Updates the nudge anchor bounds for the current hotseat and shelf bounds. void UpdateNudgeAnchorBounds(); + // Passed to |nudge_| as its tap gesture handler. + void HandleNudgeTap(); + bool nudge_allowed_for_shelf_state_ = false; HotseatWidget* const hotseat_widget_; @@ -69,6 +73,8 @@ // Observes hotseat widget to detect the hotseat bounds changes, and the // nudge widget to detect that the widget is being destroyed. ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this}; + + base::WeakPtrFactory<HomeToOverviewNudgeController> weak_factory_{this}; }; } // namespace ash
diff --git a/ash/shelf/home_to_overview_nudge_controller_unittest.cc b/ash/shelf/home_to_overview_nudge_controller_unittest.cc index 43b98f4..84de223 100644 --- a/ash/shelf/home_to_overview_nudge_controller_unittest.cc +++ b/ash/shelf/home_to_overview_nudge_controller_unittest.cc
@@ -4,6 +4,9 @@ #include "ash/shelf/home_to_overview_nudge_controller.h" +#include "ash/home_screen/home_launcher_gesture_handler.h" +#include "ash/home_screen/home_screen_controller.h" +#include "ash/home_screen/swipe_home_to_overview_controller.h" #include "ash/public/cpp/ash_features.h" #include "ash/shelf/contextual_nudge.h" #include "ash/shelf/contextual_tooltip.h" @@ -489,6 +492,138 @@ EXPECT_FALSE(GetNudgeController()->nudge_for_testing()); } +// Tests that tapping on the nudge hides the nudge. +TEST_F(HomeToOverviewNudgeControllerTest, TapOnTheNudgeClosedTheNudge) { + TabletModeControllerTestApi().EnterTabletMode(); + CreateUserSessions(1); + ScopedWindowList windows = CreateAndMinimizeWindows(2); + + ASSERT_TRUE(GetNudgeController()); + ASSERT_TRUE(GetNudgeController()->HasShowTimerForTesting()); + + GetNudgeController()->FireShowTimerForTesting(); + + ASSERT_TRUE(GetNudgeController()->nudge_for_testing()); + views::Widget* nudge_widget = GetNudgeWidget(); + WidgetCloseObserver widget_close_observer(nudge_widget); + + GetEventGenerator()->GestureTapAt( + nudge_widget->GetWindowBoundsInScreen().CenterPoint()); + + EXPECT_FALSE(GetNudgeController()->nudge_for_testing()); + EXPECT_TRUE(widget_close_observer.WidgetClosed()); + + EXPECT_EQ(gfx::Transform(), + GetHotseatWidget()->GetLayer()->GetTargetTransform()); +} + +// Tests that the nudge stops showing up if the user performs the gesture few +// times. +TEST_F(HomeToOverviewNudgeControllerTest, NoNudgeAfterSuccessfulGestures) { + TabletModeControllerTestApi().EnterTabletMode(); + CreateUserSessions(1); + ScopedWindowList windows = CreateAndMinimizeWindows(2); + + EXPECT_FALSE(GetNudgeController()->nudge_for_testing()); + + ASSERT_TRUE(GetNudgeController()->HasShowTimerForTesting()); + GetNudgeController()->FireShowTimerForTesting(); + + // Perform home to overview gesture kSuccessLimitHomeToOverview times. + for (int i = 0; i < contextual_tooltip::kSuccessLimitHomeToOverview; ++i) { + SCOPED_TRACE(testing::Message() << "Attempt " << i); + + // Perform home to overview gesture. + wm::ActivateWindow(windows[0].get()); + WindowState::Get(windows[0].get())->Minimize(); + + // Simluate swipe up and hold gesture on the home screen (which should + // transition to overview). + const gfx::Point start = GetPrimaryShelf() + ->hotseat_widget() + ->GetWindowBoundsInScreen() + .CenterPoint(); + GetEventGenerator()->GestureScrollSequenceWithCallback( + start, start + gfx::Vector2d(0, -100), + base::TimeDelta::FromMilliseconds(50), + /*num_steps = */ 12, + base::BindRepeating( + [](ui::EventType type, const gfx::Vector2dF& offset) { + if (type != ui::ET_GESTURE_SCROLL_UPDATE) + return; + + // If the swipe home to overview controller started the timer to + // transition to overview (which happens after swipe moves far + // enough), run it to trigger transition to overview. + SwipeHomeToOverviewController* swipe_controller = + Shell::Get() + ->home_screen_controller() + ->home_launcher_gesture_handler() + ->swipe_home_to_overview_controller_for_testing(); + ASSERT_TRUE(swipe_controller); + + base::OneShotTimer* transition_timer = + swipe_controller->overview_transition_timer_for_testing(); + if (transition_timer->IsRunning()) + transition_timer->FireNow(); + })); + + // No point oof continuing the test if transition to overview failed. + ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); + } + + // The nudge should not be shown next time the user transitions to home. + test_clock_.Advance(base::TimeDelta::FromHours(25)); + ScopedWindowList extra_window = CreateAndMinimizeWindows(1); + + EXPECT_FALSE(GetNudgeController()->nudge_for_testing()); + EXPECT_FALSE(GetNudgeController()->HasShowTimerForTesting()); + EXPECT_EQ(gfx::Transform(), + GetHotseatWidget()->GetLayer()->GetTargetTransform()); +} + +// Tests that swipe up and hold gesture that starts on top of contextual nudge +// widget works - i.e. that home still transitions to overview. +TEST_F(HomeToOverviewNudgeControllerTest, HomeToOverviewGestureFromNudge) { + TabletModeControllerTestApi().EnterTabletMode(); + CreateUserSessions(1); + ScopedWindowList windows = CreateAndMinimizeWindows(2); + + EXPECT_FALSE(GetNudgeController()->nudge_for_testing()); + + ASSERT_TRUE(GetNudgeController()->HasShowTimerForTesting()); + GetNudgeController()->FireShowTimerForTesting(); + + // Simluate swipe up and hold gesture on home screen from the nudge widget. + const gfx::Point start = + GetNudgeWidget()->GetWindowBoundsInScreen().CenterPoint(); + GetEventGenerator()->GestureScrollSequenceWithCallback( + start, start + gfx::Vector2d(0, -100), + base::TimeDelta::FromMilliseconds(50), + /*num_steps = */ 12, + base::BindRepeating([](ui::EventType type, const gfx::Vector2dF& offset) { + if (type != ui::ET_GESTURE_SCROLL_UPDATE) + return; + + // If the swipe home to overview controller started the timer to + // transition to overview (which happens after swipe moves far + // enough), run it to trigger transition to overview. + SwipeHomeToOverviewController* swipe_controller = + Shell::Get() + ->home_screen_controller() + ->home_launcher_gesture_handler() + ->swipe_home_to_overview_controller_for_testing(); + ASSERT_TRUE(swipe_controller); + + base::OneShotTimer* transition_timer = + swipe_controller->overview_transition_timer_for_testing(); + if (transition_timer->IsRunning()) + transition_timer->FireNow(); + })); + + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); +} + // Tests that nudge and hotseat get repositioned appropriatelly if the display // bounds change. TEST_F(HomeToOverviewNudgeControllerTest,
diff --git a/ash/shelf/hotseat_widget.cc b/ash/shelf/hotseat_widget.cc index b8d7d6d..3f66cb319 100644 --- a/ash/shelf/hotseat_widget.cc +++ b/ash/shelf/hotseat_widget.cc
@@ -84,53 +84,6 @@ } // namespace -// Records smoothness of animations for background of the hotseat widget. -class HotseatWidgetBackgroundAnimationMetricsReporter - : public HotseatTransitionAnimator::Observer, - public ui::AnimationMetricsReporter { - public: - explicit HotseatWidgetBackgroundAnimationMetricsReporter(HotseatState state) - : target_state_(state) {} - - ~HotseatWidgetBackgroundAnimationMetricsReporter() override = default; - - void OnHotseatTransitionAnimationWillStart(HotseatState from_state, - HotseatState to_state) override { - target_state_ = to_state; - } - - // ui::AnimationMetricsReporter: - void Report(int value) override { - switch (target_state_) { - case HotseatState::kShownClamshell: - case HotseatState::kShownHomeLauncher: - UMA_HISTOGRAM_PERCENTAGE( - "Ash.HotseatWidgetAnimation.TranslucentBackground." - "AnimationSmoothness.TransitionToShownHotseat", - value); - break; - case HotseatState::kExtended: - UMA_HISTOGRAM_PERCENTAGE( - "Ash.HotseatWidgetAnimation.TranslucentBackground." - "AnimationSmoothness.TransitionToExtendedHotseat", - value); - break; - case HotseatState::kHidden: - UMA_HISTOGRAM_PERCENTAGE( - "Ash.HotseatWidgetAnimation.TranslucentBackground." - "AnimationSmoothness.TransitionToHiddenHotseat", - value); - break; - default: - NOTREACHED(); - } - } - - private: - // The state to which the animation is transitioning. - HotseatState target_state_; -}; - class HotseatWidget::DelegateView : public HotseatTransitionAnimator::Observer, public views::WidgetDelegateView, public OverviewObserver, @@ -143,8 +96,7 @@ // Initializes the view. void Init(ScrollableShelfView* scrollable_shelf_view, - ui::Layer* parent_layer, - ui::AnimationMetricsReporter* background_metrics_reporter); + ui::Layer* parent_layer); // Updates the hotseat background. void UpdateTranslucentBackground(); @@ -189,8 +141,6 @@ ScrollableShelfView* scrollable_shelf_view_ = nullptr; // unowned. // Blur is disabled during animations to improve performance. bool blur_lock_ = false; - // Owned by the Hotseat Widget. - ui::AnimationMetricsReporter* background_metrics_reporter_; // The most recent color that the |translucent_background_| has been animated // to. @@ -202,7 +152,8 @@ HotseatWidget::DelegateView::~DelegateView() { WallpaperControllerImpl* wallpaper_controller = Shell::Get()->wallpaper_controller(); - OverviewController* overview_controller = Shell::Get()->overview_controller(); + OverviewController* overview_controller = + Shell::Get()->overview_controller(); if (wallpaper_controller) wallpaper_controller->RemoveObserver(this); if (overview_controller) @@ -211,13 +162,13 @@ void HotseatWidget::DelegateView::Init( ScrollableShelfView* scrollable_shelf_view, - ui::Layer* parent_layer, - ui::AnimationMetricsReporter* background_metrics_reporter) { + ui::Layer* parent_layer) { SetLayoutManager(std::make_unique<views::FillLayout>()); WallpaperControllerImpl* wallpaper_controller = Shell::Get()->wallpaper_controller(); - OverviewController* overview_controller = Shell::Get()->overview_controller(); + OverviewController* overview_controller = + Shell::Get()->overview_controller(); if (wallpaper_controller) wallpaper_controller->AddObserver(this); if (overview_controller) @@ -227,7 +178,6 @@ DCHECK(scrollable_shelf_view); scrollable_shelf_view_ = scrollable_shelf_view; UpdateTranslucentBackground(); - background_metrics_reporter_ = background_metrics_reporter; } void HotseatWidget::DelegateView::UpdateTranslucentBackground() { @@ -262,8 +212,6 @@ animation_setter.SetTweenType(gfx::Tween::EASE_OUT); animation_setter.SetPreemptionStrategy( ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - if (animate) - animation_setter.SetAnimationMetricsReporter(background_metrics_reporter_); if (ShelfConfig::Get()->GetDefaultShelfColor() != target_color_) { target_color_ = ShelfConfig::Get()->GetDefaultShelfColor(); @@ -368,11 +316,7 @@ scrollable_shelf_view_ = GetContentsView()->AddChildView( std::make_unique<ScrollableShelfView>(ShelfModel::Get(), shelf)); scrollable_shelf_view_->Init(); - traslucent_background_metrics_reporter_ = - std::make_unique<HotseatWidgetBackgroundAnimationMetricsReporter>( - state()); - delegate_view_->Init(scrollable_shelf_view(), GetLayer(), - traslucent_background_metrics_reporter_.get()); + delegate_view_->Init(scrollable_shelf_view(), GetLayer()); } void HotseatWidget::OnHotseatTransitionAnimatorCreated(
diff --git a/ash/shelf/hotseat_widget.h b/ash/shelf/hotseat_widget.h index 940cf26..2acc36d67 100644 --- a/ash/shelf/hotseat_widget.h +++ b/ash/shelf/hotseat_widget.h
@@ -23,7 +23,6 @@ class Shelf; class ShelfView; class HotseatTransitionAnimator; -class HotseatWidgetBackgroundAnimationMetricsReporter; // The hotseat widget is part of the shelf and hosts app shortcuts. class ASH_EXPORT HotseatWidget : public ShelfComponent, @@ -159,11 +158,6 @@ // during an animation. std::unique_ptr<aura::ScopedWindowTargeter> hotseat_window_targeter_; - // Metrics reporter for animations of the traslucent background in the - // hotseat. - std::unique_ptr<HotseatWidgetBackgroundAnimationMetricsReporter> - traslucent_background_metrics_reporter_; - DISALLOW_COPY_AND_ASSIGN(HotseatWidget); };
diff --git a/ash/shelf/login_shelf_gesture_controller.cc b/ash/shelf/login_shelf_gesture_controller.cc index 2b75692..3fa8bd7 100644 --- a/ash/shelf/login_shelf_gesture_controller.cc +++ b/ash/shelf/login_shelf_gesture_controller.cc
@@ -43,7 +43,8 @@ is_oobe ? gfx::kGoogleGrey700 : gfx::kGoogleGrey100; nudge_ = new ContextualNudge(drag_handle, nullptr /*parent_window*/, ContextualNudge::Position::kTop, gfx::Insets(4), - gesture_nudge, nudge_text_color); + gesture_nudge, nudge_text_color, + base::RepeatingClosure()); nudge_->GetWidget()->Show(); nudge_->GetWidget()->AddObserver(this); }
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc index 45eeb8d0..a88e0d7 100644 --- a/ash/shelf/shelf.cc +++ b/ash/shelf/shelf.cc
@@ -79,19 +79,19 @@ case HotseatState::kShownClamshell: case HotseatState::kShownHomeLauncher: UMA_HISTOGRAM_PERCENTAGE( - "Ash.HotseatWidgetAnimation.Widget.AnimationSmoothness." + "Ash.HotseatWidgetAnimation.AnimationSmoothness." "TransitionToShownHotseat", value); break; case HotseatState::kExtended: UMA_HISTOGRAM_PERCENTAGE( - "Ash.HotseatWidgetAnimation.Widget.AnimationSmoothness." + "Ash.HotseatWidgetAnimation.AnimationSmoothness." "TransitionToExtendedHotseat", value); break; case HotseatState::kHidden: UMA_HISTOGRAM_PERCENTAGE( - "Ash.HotseatWidgetAnimation.Widget.AnimationSmoothness." + "Ash.HotseatWidgetAnimation.AnimationSmoothness." "TransitionToHiddenHotseat", value); break;
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc index 20c33eb1..30ddfa5 100644 --- a/ash/system/palette/palette_tray_unittest.cc +++ b/ash/system/palette/palette_tray_unittest.cc
@@ -311,6 +311,9 @@ EXPECT_EQ(expected, highlighter_showing()); EXPECT_EQ(expected, metalayer_enabled()); generator->ReleaseTouch(); + // If the tool is not enabled, the gesture may open a context menu instead. + // Press escape to close the menu. + generator->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE); } void WaitDragAndAssertMetalayer(const std::string& context,
diff --git a/ash/system/palette/tools/metalayer_mode.cc b/ash/system/palette/tools/metalayer_mode.cc index b02fdaa..22b8d6c 100644 --- a/ash/system/palette/tools/metalayer_mode.cc +++ b/ash/system/palette/tools/metalayer_mode.cc
@@ -150,6 +150,19 @@ event->StopPropagation(); } +void MetalayerMode::OnGestureEvent(ui::GestureEvent* event) { + if (!feature_enabled()) + return; + + // When the stylus button is pressed, a ET_GESTURE_LONG_PRESS event with + // EF_LEFT_MOUSE_BUTTON will be generated by the GestureDetector. If the + // metalayer feature is enabled, these should be consumed. + if (event->type() == ui::ET_GESTURE_LONG_PRESS && + (event->flags() & ui::EF_LEFT_MOUSE_BUTTON)) { + event->StopPropagation(); + } +} + void MetalayerMode::OnAssistantStatusChanged(mojom::AssistantState state) { assistant_state_ = state; UpdateState();
diff --git a/ash/system/palette/tools/metalayer_mode.h b/ash/system/palette/tools/metalayer_mode.h index fe24116..b802fea 100644 --- a/ash/system/palette/tools/metalayer_mode.h +++ b/ash/system/palette/tools/metalayer_mode.h
@@ -62,6 +62,7 @@ // ui::EventHandler: void OnTouchEvent(ui::TouchEvent* event) override; + void OnGestureEvent(ui::GestureEvent* event) override; // AssistantStateObserver: void OnAssistantStatusChanged(mojom::AssistantState state) override;
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc index f73b32c..c642731 100644 --- a/ash/wm/overview/overview_session_unittest.cc +++ b/ash/wm/overview/overview_session_unittest.cc
@@ -5957,7 +5957,7 @@ EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - // 8. Test if splitview is active, open the app list will end overview if + // 8. Test if splitview is not active, open the app list will end overview if // overview is active. ToggleOverview(); // Open app list.
diff --git a/base/BUILD.gn b/base/BUILD.gn index e0833b5..3b5f788 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -28,6 +28,7 @@ import("//build/config/jumbo.gni") import("//build/config/logging.gni") import("//build/config/nacl/config.gni") +import("//build/config/profiling/profiling.gni") import("//build/config/sysroot.gni") import("//build/config/ui.gni") import("//build/nocompile.gni") @@ -1303,7 +1304,7 @@ ":base_static", ":build_date", ":cfi_buildflags", - ":clang_coverage_buildflags", + ":clang_profiling_buildflags", ":debugging_buildflags", ":logging_buildflags", ":orderfile_buildflags", @@ -1359,11 +1360,11 @@ } } - if (use_clang_coverage) { - # Call-sites use this conditional on the CLANG_COVERAGE macro, for clarity. + if (use_clang_profiling) { + # Call-sites use this conditional on the CLANG_PROFILING macro, for clarity. sources += [ - "test/clang_coverage.cc", - "test/clang_coverage.h", + "test/clang_profiling.cc", + "test/clang_profiling.h", ] } @@ -2166,13 +2167,13 @@ flags = [ "USE_PARTITION_ALLOC=$use_partition_alloc" ] } -buildflag_header("clang_coverage_buildflags") { - header = "clang_coverage_buildflags.h" +buildflag_header("clang_profiling_buildflags") { + header = "clang_profiling_buildflags.h" header_dir = "base" flags = [ - "CLANG_COVERAGE=$use_clang_coverage", - "CLANG_COVERAGE_INSIDE_SANDBOX=$use_clang_coverage_inside_sandbox", + "CLANG_PROFILING=$use_clang_profiling", + "CLANG_PROFILING_INSIDE_SANDBOX=$use_clang_profiling_inside_sandbox", ] }
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc index 341b6cfa..eac4b5f 100644 --- a/base/base_paths_win.cc +++ b/base/base_paths_win.cc
@@ -9,9 +9,12 @@ #include "base/base_paths.h" #include "base/environment.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/location.h" #include "base/path_service.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/threading/thread_restrictions.h" #include "base/win/current_module.h" #include "base/win/scoped_co_mem.h" #include "base/win/windows_version.h" @@ -172,12 +175,19 @@ .Append(FILE_PATH_LITERAL("Internet Explorer")) .Append(FILE_PATH_LITERAL("Quick Launch")); break; - case base::DIR_TASKBAR_PINS: + case base::DIR_TASKBAR_PINS: { if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur)) return false; cur = cur.Append(FILE_PATH_LITERAL("User Pinned")) .Append(FILE_PATH_LITERAL("TaskBar")); + // Allow a blocking call here to check for existence of the directory. In + // practice, all uses of SHGetFolderPath in this function make a similar + // check, so this does not add new I/O that wasn't already happening. + ScopedAllowBlocking allow_blocking(FROM_HERE); + if (!DirectoryExists(cur)) + return false; break; + } case base::DIR_IMPLICIT_APP_SHORTCUTS: if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur)) return false;
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc index 8a7858d9..1982173 100644 --- a/base/debug/debugger_posix.cc +++ b/base/debug/debugger_posix.cc
@@ -17,7 +17,7 @@ #include <memory> #include <vector> -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/stl_util.h" #include "base/threading/platform_thread.h" #include "base/time/time.h" @@ -56,8 +56,8 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" -#if BUILDFLAG(CLANG_COVERAGE) -#include "base/test/clang_coverage.h" +#if BUILDFLAG(CLANG_PROFILING) +#include "base/test/clang_profiling.h" #endif #if defined(USE_SYMBOLIZE) @@ -324,8 +324,8 @@ #endif void BreakDebugger() { -#if BUILDFLAG(CLANG_COVERAGE) - WriteClangCoverageProfile(); +#if BUILDFLAG(CLANG_PROFILING) + WriteClangProfilingProfile(); #endif // NOTE: This code MUST be async-signal safe (it's used by in-process
diff --git a/base/debug/debugger_win.cc b/base/debug/debugger_win.cc index fd10b4b..2e3875b 100644 --- a/base/debug/debugger_win.cc +++ b/base/debug/debugger_win.cc
@@ -7,10 +7,10 @@ #include <stdlib.h> #include <windows.h> -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" -#if BUILDFLAG(CLANG_COVERAGE) -#include "base/test/clang_coverage.h" +#if BUILDFLAG(CLANG_PROFILING) +#include "base/test/clang_profiling.h" #endif namespace base { @@ -21,8 +21,8 @@ } void BreakDebugger() { -#if BUILDFLAG(CLANG_COVERAGE) - WriteClangCoverageProfile(); +#if BUILDFLAG(CLANG_PROFILING) + WriteClangProfilingProfile(); #endif if (IsDebugUISuppressed())
diff --git a/base/process/process_fuchsia.cc b/base/process/process_fuchsia.cc index f260575..516a067 100644 --- a/base/process/process_fuchsia.cc +++ b/base/process/process_fuchsia.cc
@@ -8,14 +8,14 @@ #include <zircon/process.h> #include <zircon/syscalls.h> -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/debug/activity_tracker.h" #include "base/fuchsia/default_job.h" #include "base/fuchsia/fuchsia_logging.h" #include "base/strings/stringprintf.h" -#if BUILDFLAG(CLANG_COVERAGE) -#include "base/test/clang_coverage.h" +#if BUILDFLAG(CLANG_PROFILING) +#include "base/test/clang_profiling.h" #endif namespace base { @@ -93,8 +93,8 @@ // static void Process::TerminateCurrentProcessImmediately(int exit_code) { -#if BUILDFLAG(CLANG_COVERAGE) - WriteClangCoverageProfile(); +#if BUILDFLAG(CLANG_PROFILING) + WriteClangProfilingProfile(); #endif _exit(exit_code); }
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc index 9636d44..17dae528 100644 --- a/base/process/process_posix.cc +++ b/base/process/process_posix.cc
@@ -10,7 +10,7 @@ #include <sys/resource.h> #include <sys/wait.h> -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/debug/activity_tracker.h" #include "base/files/scoped_file.h" #include "base/logging.h" @@ -23,8 +23,8 @@ #include <sys/event.h> #endif -#if BUILDFLAG(CLANG_COVERAGE) -#include "base/test/clang_coverage.h" +#if BUILDFLAG(CLANG_PROFILING) +#include "base/test/clang_profiling.h" #endif namespace { @@ -276,8 +276,8 @@ // static void Process::TerminateCurrentProcessImmediately(int exit_code) { -#if BUILDFLAG(CLANG_COVERAGE) - WriteClangCoverageProfile(); +#if BUILDFLAG(CLANG_PROFILING) + WriteClangProfilingProfile(); #endif _exit(exit_code); }
diff --git a/base/process/process_win.cc b/base/process/process_win.cc index 4f2ccf96..85688b7 100644 --- a/base/process/process_win.cc +++ b/base/process/process_win.cc
@@ -4,7 +4,7 @@ #include "base/process/process.h" -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/debug/activity_tracker.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" @@ -13,8 +13,8 @@ #include <windows.h> -#if BUILDFLAG(CLANG_COVERAGE) -#include "base/test/clang_coverage.h" +#if BUILDFLAG(CLANG_PROFILING) +#include "base/test/clang_profiling.h" #endif namespace { @@ -90,8 +90,8 @@ // static void Process::TerminateCurrentProcessImmediately(int exit_code) { -#if BUILDFLAG(CLANG_COVERAGE) - WriteClangCoverageProfile(); +#if BUILDFLAG(CLANG_PROFILING) + WriteClangProfilingProfile(); #endif ::TerminateProcess(GetCurrentProcess(), exit_code); // There is some ambiguity over whether the call above can return. Rather than
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn index 712c70899..7a88a66a 100644 --- a/base/test/BUILD.gn +++ b/base/test/BUILD.gn
@@ -26,7 +26,7 @@ ] deps = [ "//base", - "//base:clang_coverage_buildflags", + "//base:clang_profiling_buildflags", ] }
diff --git a/base/test/clang_coverage.cc b/base/test/clang_coverage.cc deleted file mode 100644 index 33f823e..0000000 --- a/base/test/clang_coverage.cc +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/clang_coverage.h" - -#include "base/no_destructor.h" -#include "base/synchronization/lock.h" - -extern "C" int __llvm_profile_dump(void); - -namespace base { - -void WriteClangCoverageProfile() { - // __llvm_profile_dump() guarantees that it will not dump coverage information - // if it is being called twice or more. However, it is not thread safe, as it - // is supposed to be called from atexit() handler rather than being called - // directly from random places. Since we have to call it ourselves, we must - // ensure thread safety in order to prevent duplication of coverage counters. - static base::NoDestructor<base::Lock> lock; - base::AutoLock auto_lock(*lock); - __llvm_profile_dump(); -} - -} // namespace base
diff --git a/base/test/clang_coverage.h b/base/test/clang_coverage.h deleted file mode 100644 index ed2e3d7..0000000 --- a/base/test/clang_coverage.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TEST_CLANG_COVERAGE_H_ -#define BASE_TEST_CLANG_COVERAGE_H_ - -#include "base/clang_coverage_buildflags.h" - -#if !BUILDFLAG(CLANG_COVERAGE) -#error "Clang coverage can only be used if CLANG_COVERAGE macro is defined" -#endif - -namespace base { - -// Write out the accumulated code coverage profile to the configured file. -// This is used internally by e.g. base::Process and FATAL logging, to cause -// coverage information to be stored even when performing an "immediate" exit -// (or triggering a debug crash), where the automatic at-exit writer will not -// be invoked. -// This call is thread-safe, and will write profiling data at-most-once. -void WriteClangCoverageProfile(); - -} // namespace base - -#endif // BASE_TEST_CLANG_COVERAGE_H_
diff --git a/base/test/clang_profiling.cc b/base/test/clang_profiling.cc new file mode 100644 index 0000000..5681a10 --- /dev/null +++ b/base/test/clang_profiling.cc
@@ -0,0 +1,26 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/test/clang_profiling.h" + +#include "base/no_destructor.h" +#include "base/synchronization/lock.h" + +extern "C" int __llvm_profile_dump(void); + +namespace base { + +void WriteClangProfilingProfile() { + // __llvm_profile_dump() guarantees that it will not dump profiling + // information if it is being called twice or more. However, it is not thread + // safe, as it is supposed to be called from atexit() handler rather than + // being called directly from random places. Since we have to call it + // ourselves, we must ensure thread safety in order to prevent duplication of + // profiling counters. + static base::NoDestructor<base::Lock> lock; + base::AutoLock auto_lock(*lock); + __llvm_profile_dump(); +} + +} // namespace base
diff --git a/base/test/clang_profiling.h b/base/test/clang_profiling.h new file mode 100644 index 0000000..1ecc02d --- /dev/null +++ b/base/test/clang_profiling.h
@@ -0,0 +1,26 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_TEST_CLANG_PROFILING_H_ +#define BASE_TEST_CLANG_PROFILING_H_ + +#include "base/clang_profiling_buildflags.h" + +#if !BUILDFLAG(CLANG_PROFILING) +#error "Clang profiling can only be used if CLANG_PROFILING macro is defined" +#endif + +namespace base { + +// Write out the accumulated code profiling profile to the configured file. +// This is used internally by e.g. base::Process and FATAL logging, to cause +// profiling information to be stored even when performing an "immediate" exit +// (or triggering a debug crash), where the automatic at-exit writer will not +// be invoked. +// This call is thread-safe, and will write profiling data at-most-once. +void WriteClangProfilingProfile(); + +} // namespace base + +#endif // BASE_TEST_CLANG_PROFILING_H_
diff --git a/base/test/test_timeouts.cc b/base/test/test_timeouts.cc index ef612bb..e77f175 100644 --- a/base/test/test_timeouts.cc +++ b/base/test/test_timeouts.cc
@@ -7,7 +7,7 @@ #include <algorithm> #include <string> -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/command_line.h" #include "base/debug/debugger.h" #include "base/logging.h" @@ -57,7 +57,7 @@ constexpr int kTimeoutMultiplier = 3; #elif defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) constexpr int kTimeoutMultiplier = 2; -#elif BUILDFLAG(CLANG_COVERAGE) +#elif BUILDFLAG(CLANG_PROFILING) // On coverage build, tests run 3x slower. constexpr int kTimeoutMultiplier = 3; #elif !defined(NDEBUG) && defined(OS_CHROMEOS)
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h index 6833031..25e1c98 100644 --- a/base/threading/thread_restrictions.h +++ b/base/threading/thread_restrictions.h
@@ -303,12 +303,15 @@ class AdjustOOMScoreHelper; class FileDescriptorWatcher; +class FilePath; class GetAppOutputScopedAllowBaseSyncPrimitives; class ScopedAllowThreadRecallForStackSamplingProfiler; class SimpleThread; class StackSamplingProfiler; class Thread; +bool PathProviderWin(int, FilePath*); + #if DCHECK_IS_ON() #define INLINE_IF_DCHECK_IS_OFF BASE_EXPORT #define EMPTY_BODY_IF_DCHECK_IS_OFF @@ -376,6 +379,8 @@ friend class content::RenderProcessHostImpl; friend class weblayer::WebLayerPathProvider; + friend bool PathProviderWin(int, FilePath*); + ScopedAllowBlocking(const Location& from_here = Location::Current()); ~ScopedAllowBlocking();
diff --git a/build/android/pylib/base/test_instance_factory.py b/build/android/pylib/base/test_instance_factory.py index 60fea1ba..cb34956d 100644 --- a/build/android/pylib/base/test_instance_factory.py +++ b/build/android/pylib/base/test_instance_factory.py
@@ -5,7 +5,6 @@ from pylib.gtest import gtest_test_instance from pylib.instrumentation import instrumentation_test_instance from pylib.junit import junit_test_instance -from pylib.linker import linker_test_instance from pylib.monkey import monkey_test_instance from pylib.utils import device_dependencies @@ -20,8 +19,6 @@ args, device_dependencies.GetDataDependencies, error_func) elif args.command == 'junit': return junit_test_instance.JunitTestInstance(args, error_func) - elif args.command == 'linker': - return linker_test_instance.LinkerTestInstance(args) elif args.command == 'monkey': return monkey_test_instance.MonkeyTestInstance(args, error_func)
diff --git a/build/android/pylib/base/test_run_factory.py b/build/android/pylib/base/test_run_factory.py index dc74644..df6eeb8f 100644 --- a/build/android/pylib/base/test_run_factory.py +++ b/build/android/pylib/base/test_run_factory.py
@@ -5,12 +5,10 @@ from pylib.gtest import gtest_test_instance from pylib.instrumentation import instrumentation_test_instance from pylib.junit import junit_test_instance -from pylib.linker import linker_test_instance from pylib.monkey import monkey_test_instance from pylib.local.device import local_device_environment from pylib.local.device import local_device_gtest_run from pylib.local.device import local_device_instrumentation_test_run -from pylib.local.device import local_device_linker_test_run from pylib.local.device import local_device_monkey_test_run from pylib.local.machine import local_machine_environment from pylib.local.machine import local_machine_junit_test_run @@ -24,9 +22,6 @@ instrumentation_test_instance.InstrumentationTestInstance): return (local_device_instrumentation_test_run .LocalDeviceInstrumentationTestRun(env, test_instance)) - if isinstance(test_instance, linker_test_instance.LinkerTestInstance): - return (local_device_linker_test_run - .LocalDeviceLinkerTestRun(env, test_instance)) if isinstance(test_instance, monkey_test_instance.MonkeyTestInstance): return (local_device_monkey_test_run .LocalDeviceMonkeyTestRun(env, test_instance))
diff --git a/build/android/pylib/linker/__init__.py b/build/android/pylib/linker/__init__.py deleted file mode 100644 index 9228df89..0000000 --- a/build/android/pylib/linker/__init__.py +++ /dev/null
@@ -1,3 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file.
diff --git a/build/android/pylib/linker/linker_test_instance.py b/build/android/pylib/linker/linker_test_instance.py deleted file mode 100644 index 53978cb..0000000 --- a/build/android/pylib/linker/linker_test_instance.py +++ /dev/null
@@ -1,48 +0,0 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -from pylib.base import test_instance -from pylib.constants import host_paths -from pylib.linker import test_case -from pylib.utils import test_filter - -with host_paths.SysPath(host_paths.BUILD_COMMON_PATH): - import unittest_util - - -class LinkerTestInstance(test_instance.TestInstance): - - def __init__(self, args): - super(LinkerTestInstance, self).__init__() - self._test_apk = args.test_apk - self._test_filter = test_filter.InitializeFilterFromArgs(args) - - @property - def test_apk(self): - return self._test_apk - - @property - def test_filter(self): - return self._test_filter - - def GetTests(self): - tests = [test_case.LinkerSharedRelroTest()] - - if self._test_filter: - filtered_names = unittest_util.FilterTestNames( - (t.qualified_name for t in tests), self._test_filter) - tests = [ - t for t in tests - if t.qualified_name in filtered_names] - - return tests - - def SetUp(self): - pass - - def TearDown(self): - pass - - def TestType(self): - return 'linker'
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py deleted file mode 100644 index 47933c2..0000000 --- a/build/android/pylib/linker/test_case.py +++ /dev/null
@@ -1,199 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Base class for linker-specific test cases. - - The custom dynamic linker can only be tested through a custom test case - for various technical reasons: - - - It's an 'invisible feature', i.e. it doesn't expose a new API or - behaviour, all it does is save RAM when loading native libraries. - - - Checking that it works correctly requires several things that do not - fit the existing GTest-based and instrumentation-based tests: - - - Native test code needs to be run in both the browser and renderer - process at the same time just after loading native libraries, in - a completely asynchronous way. - - - Each test case requires restarting a whole new application process - with a different command-line. - - - Enabling test support in the Linker code requires building a special - APK with a flag to activate special test-only support code in the - Linker code itself. - - Host-driven tests have also been tried, but since they're really - sub-classes of instrumentation tests, they didn't work well either. - - To build and run, refer to android_linker_testing.md. -""" -# pylint: disable=R0201 - -from __future__ import print_function - -import logging -import re - -from devil.android import device_errors -from devil.android.sdk import intent -from pylib.base import base_test_result - - -ResultType = base_test_result.ResultType - -_PACKAGE_NAME = 'org.chromium.chromium_linker_test_apk' -_ACTIVITY_NAME = '.ChromiumLinkerTestActivity' - -# Logcat filters used during each test. Only the 'chromium' one is really -# needed, but the logs are added to the TestResult in case of error, and -# it is handy to have others as well when troubleshooting. -_LOGCAT_FILTERS = ['*:s', 'chromium:v', 'cr_chromium:v', - 'cr_ChromiumAndroidLinker:v', 'cr_LibraryLoader:v', - 'cr_LinkerTest:v'] -#_LOGCAT_FILTERS = ['*:v'] ## DEBUG - -# Regular expression used to match status lines in logcat. -_RE_BROWSER_STATUS_LINE = re.compile(r' BROWSER_LINKER_TEST: (FAIL|SUCCESS)$') -_RE_RENDERER_STATUS_LINE = re.compile(r' RENDERER_LINKER_TEST: (FAIL|SUCCESS)$') - -def _StartActivityAndWaitForLinkerTestStatus(device, timeout): - """Force-start an activity and wait up to |timeout| seconds until the full - linker test status lines appear in the logcat, recorded through |device|. - Args: - device: A DeviceUtils instance. - timeout: Timeout in seconds - Returns: - A (status, logs) tuple, where status is a ResultType constant, and logs - if the final logcat output as a string. - """ - - # 1. Start recording logcat with appropriate filters. - with device.GetLogcatMonitor(filter_specs=_LOGCAT_FILTERS) as logmon: - - # 2. Force-start activity. - device.StartActivity( - intent.Intent(package=_PACKAGE_NAME, activity=_ACTIVITY_NAME), - force_stop=True) - - # 3. Wait up to |timeout| seconds until the test status is in the logcat. - result = ResultType.PASS - try: - browser_match = logmon.WaitFor(_RE_BROWSER_STATUS_LINE, timeout=timeout) - logging.debug('Found browser match: %s', browser_match.group(0)) - renderer_match = logmon.WaitFor(_RE_RENDERER_STATUS_LINE, - timeout=timeout) - logging.debug('Found renderer match: %s', renderer_match.group(0)) - if (browser_match.group(1) != 'SUCCESS' - or renderer_match.group(1) != 'SUCCESS'): - result = ResultType.FAIL - except device_errors.CommandTimeoutError: - result = ResultType.TIMEOUT - - logcat = device.adb.Logcat(dump=True) - - logmon.Close() - return result, '\n'.join(logcat) - - -class LibraryLoadMap(dict): - """A helper class to pretty-print a map of library names to load addresses.""" - def __str__(self): - items = ['\'%s\': 0x%x' % (name, address) for \ - (name, address) in self.iteritems()] - return '{%s}' % (', '.join(items)) - - def __repr__(self): - return 'LibraryLoadMap(%s)' % self.__str__() - - -class AddressList(list): - """A helper class to pretty-print a list of load addresses.""" - def __str__(self): - items = ['0x%x' % address for address in self] - return '[%s]' % (', '.join(items)) - - def __repr__(self): - return 'AddressList(%s)' % self.__str__() - - -class LinkerTestCaseBase(object): - """Base class for linker test cases.""" - - def __init__(self): - """Creates a test case.""" - test_suffix = 'ForLegacyLinker' - class_name = self.__class__.__name__ - self.qualified_name = '%s.%s' % (class_name, test_suffix) - self.tagged_name = self.qualified_name - - def _RunTest(self, _device): - """Runs the test, must be overridden. - Args: - _device: A DeviceUtils interface. - Returns: - A (status, log) tuple, where <status> is a ResultType constant, and <log> - is the logcat output captured during the test in case of error, or None - in case of success. - """ - return ResultType.FAIL, 'Unimplemented _RunTest() method!' - - def Run(self, device): - """Runs the test on a given device. - Args: - device: Name of target device where to run the test. - Returns: - A base_test_result.TestRunResult() instance. - """ - margin = 8 - print('[ %-*s ] %s' % (margin, 'RUN', self.tagged_name)) - logging.info('Running linker test: %s', self.tagged_name) - - # Run the test. - status, logs = self._RunTest(device) - - result_text = 'OK' - if status == ResultType.FAIL: - result_text = 'FAILED' - elif status == ResultType.TIMEOUT: - result_text = 'TIMEOUT' - print('[ %*s ] %s' % (margin, result_text, self.tagged_name)) - - return base_test_result.BaseTestResult(self.tagged_name, status, log=logs) - - - def __str__(self): - return self.tagged_name - - def __repr__(self): - return self.tagged_name - - -class LinkerSharedRelroTest(LinkerTestCaseBase): - """A linker test case to check the status of shared RELRO sections. - - The core of the checks performed here are pretty simple: - - - Clear the logcat and start recording with an appropriate set of filters. - - Create the command-line appropriate for the test-case. - - Start the activity (always forcing a cold start). - - Every second, look at the current content of the filtered logcat lines - and look for instances of the following: - - BROWSER_LINKER_TEST: <status> - RENDERER_LINKER_TEST: <status> - - where <status> can be either FAIL or SUCCESS. These lines can appear - in any order in the logcat. Once both browser and renderer status are - found, stop the loop. Otherwise timeout after 30 seconds. - - Note that there can be other lines beginning with BROWSER_LINKER_TEST: - and RENDERER_LINKER_TEST:, but are not followed by a <status> code. - - - The test case passes if the <status> for both the browser and renderer - process are SUCCESS. Otherwise its a fail. - """ - def _RunTest(self, device): - # Wait up to 30 seconds until the linker test status is in the logcat. - return _StartActivityAndWaitForLinkerTestStatus(device, timeout=30)
diff --git a/build/android/pylib/local/device/local_device_linker_test_run.py b/build/android/pylib/local/device/local_device_linker_test_run.py deleted file mode 100644 index 2a1520e..0000000 --- a/build/android/pylib/local/device/local_device_linker_test_run.py +++ /dev/null
@@ -1,75 +0,0 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import logging -import sys -import traceback - -from pylib.base import base_test_result -from pylib.linker import test_case -from pylib.local.device import local_device_environment -from pylib.local.device import local_device_test_run - - -class LinkerExceptionTestResult(base_test_result.BaseTestResult): - """Test result corresponding to a python exception in a host-custom test.""" - - def __init__(self, test_name, exc_info): - """Constructs a LinkerExceptionTestResult object. - - Args: - test_name: name of the test which raised an exception. - exc_info: exception info, ostensibly from sys.exc_info(). - """ - exc_type, exc_value, exc_traceback = exc_info - trace_info = ''.join(traceback.format_exception(exc_type, exc_value, - exc_traceback)) - log_msg = 'Exception:\n' + trace_info - - super(LinkerExceptionTestResult, self).__init__( - test_name, - base_test_result.ResultType.FAIL, - log="%s %s" % (exc_type, log_msg)) - - -class LocalDeviceLinkerTestRun(local_device_test_run.LocalDeviceTestRun): - - def _CreateShards(self, tests): - return tests - - def _GetTests(self): - return self._test_instance.GetTests() - - def _GetUniqueTestName(self, test): - return test.qualified_name - - def _RunTest(self, device, test): - assert isinstance(test, test_case.LinkerTestCaseBase) - - try: - result = test.Run(device) - except Exception: # pylint: disable=broad-except - logging.exception('Caught exception while trying to run test: ' + - test.tagged_name) - exc_info = sys.exc_info() - result = LinkerExceptionTestResult(test.tagged_name, exc_info) - - return result, None - - def SetUp(self): - @local_device_environment.handle_shard_failures_with( - on_failure=self._env.BlacklistDevice) - def individual_device_set_up(dev): - dev.Install(self._test_instance.test_apk) - - self._env.parallel_devices.pMap(individual_device_set_up) - - def _ShouldShard(self): - return True - - def TearDown(self): - pass - - def TestPackage(self): - pass
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps index 29802b6..94a99a9 100644 --- a/build/android/test_runner.pydeps +++ b/build/android/test_runner.pydeps
@@ -160,15 +160,11 @@ pylib/instrumentation/test_result.py pylib/junit/__init__.py pylib/junit/junit_test_instance.py -pylib/linker/__init__.py -pylib/linker/linker_test_instance.py -pylib/linker/test_case.py pylib/local/__init__.py pylib/local/device/__init__.py pylib/local/device/local_device_environment.py pylib/local/device/local_device_gtest_run.py pylib/local/device/local_device_instrumentation_test_run.py -pylib/local/device/local_device_linker_test_run.py pylib/local/device/local_device_monkey_test_run.py pylib/local/device/local_device_test_run.py pylib/local/emulator/__init__.py
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 42667ab..9573394 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -499,12 +499,6 @@ "-Xclang", "-instcombine-lower-dbg-declare=0", ] - - if (!is_chromeos && default_toolchain != "//build/toolchain/cros:target") { - # TODO(https://crbug.com/1049161): Remove '-DCLANG_SPAWN_CC1=ON' from build.py instead - # once this change has marinated a bit. - cflags += [ "-fintegrated-cc1" ] - } } # C11/C++11 compiler flags setup.
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni index 0ef29cf..f62f305 100644 --- a/build/config/ios/rules.gni +++ b/build/config/ios/rules.gni
@@ -1204,10 +1204,6 @@ get_label_info("$_target_name($default_toolchain)", "target_gen_dir") _framework_headers_target = _target_name + "_framework_headers" - _framework_headers_config = _target_name + "_framework_headers_config" - config(_framework_headers_config) { - framework_dirs = [ _default_toolchain_root_out_dir ] - } _headers_map_config = _target_name + "_headers_map" _header_map_filename = @@ -1218,6 +1214,11 @@ } } + _framework_headers_config = _target_name + "_framework_headers_config" + config(_framework_headers_config) { + framework_dirs = [ _default_toolchain_root_out_dir ] + } + _arch_shared_library_source = _target_name + "_arch_shared_library_sources" _arch_shared_library_target = _target_name + "_arch_shared_library" _lipo_shared_library_target = _target_name + "_shared_library"
diff --git a/build/config/profiling/OWNERS b/build/config/profiling/OWNERS new file mode 100644 index 0000000..225ce18 --- /dev/null +++ b/build/config/profiling/OWNERS
@@ -0,0 +1,3 @@ +liaoyuke@chromium.org +sajjadm@chromium.org +sebmarchand@chromium.org
diff --git a/build/config/profiling/profiling.gni b/build/config/profiling/profiling.gni new file mode 100644 index 0000000..7dca6eac --- /dev/null +++ b/build/config/profiling/profiling.gni
@@ -0,0 +1,12 @@ +# Copyright 2020 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/coverage/coverage.gni") + +declare_args() { + use_clang_profiling = use_clang_coverage +} + +assert(!use_clang_profiling || is_clang, + "Clang Source-based profiling requires clang.")
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni index 262f868..f0cfd8a 100644 --- a/build/config/sanitizers/sanitizers.gni +++ b/build/config/sanitizers/sanitizers.gni
@@ -5,7 +5,7 @@ import("//build/config/chrome_build.gni") import("//build/config/chromecast_build.gni") import("//build/config/chromeos/args.gni") -import("//build/config/coverage/coverage.gni") +import("//build/config/profiling/profiling.gni") import("//build/toolchain/toolchain.gni") declare_args() { @@ -167,7 +167,8 @@ # work well for fuzzing builds. Since fuzzing builds already disable the # sandbox when dumping coverage, limit the sandbox-only path to non-fuzzing # builds. - use_clang_coverage_inside_sandbox = use_clang_coverage && !use_fuzzing_engine + use_clang_profiling_inside_sandbox = + use_clang_profiling && !use_fuzzing_engine # Detect overflow/underflow for global objects. #
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 0f152dd83..5c35c82b 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -0.20200311.0.1 \ No newline at end of file +0.20200311.1.1 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 6f4b47690..5c35c82b 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -0.20200310.3.1 \ No newline at end of file +0.20200311.1.1 \ No newline at end of file
diff --git a/build/toolchain/clang_code_coverage_wrapper.py b/build/toolchain/clang_code_coverage_wrapper.py index 7d6a514e..757c0c9 100755 --- a/build/toolchain/clang_code_coverage_wrapper.py +++ b/build/toolchain/clang_code_coverage_wrapper.py
@@ -123,13 +123,13 @@ # Map of force lists indexed by target OS. _COVERAGE_FORCE_LIST_MAP = { - # clang_coverage.cc refers to the symbol `__llvm_profile_dump` from the + # clang_profiling.cc refers to the symbol `__llvm_profile_dump` from the # profiling runtime. In a partial coverage build, it is possible for a - # binary to include clang_coverage.cc but have no instrumented files, thus + # binary to include clang_profiling.cc but have no instrumented files, thus # causing an unresolved symbol error because the profiling runtime will not # be linked in. Therefore we force coverage for this file to ensure that # any target that includes it will also get the profiling runtime. - 'win': [r'..\..\base\test\clang_coverage.cc'], + 'win': [r'..\..\base\test\clang_profiling.cc'], }
diff --git a/build/util/version.gni b/build/util/version.gni index 77bd9dd8..4cdb682 100644 --- a/build/util/version.gni +++ b/build/util/version.gni
@@ -56,7 +56,7 @@ target_cpu, ] - if (!public_android_sdk) { + if (defined(public_android_sdk) && !public_android_sdk) { _script_arguments += [ "--next" ] } }
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni index ca12389..a7e6abcb 100644 --- a/chrome/android/chrome_junit_test_java_sources.gni +++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -205,6 +205,7 @@ "junit/src/org/chromium/chrome/browser/tab/TabBrowserControlsConstraintsHelperTest.java", "junit/src/org/chromium/chrome/browser/tab/TabBrowserControlsOffsetHelperTest.java", "junit/src/org/chromium/chrome/browser/tab/TabUnitTest.java", + "junit/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegateTest.java", "junit/src/org/chromium/chrome/browser/tabstate/TabStateUnitTest.java", "junit/src/org/chromium/chrome/browser/tasks/EngagementTimeUtilTest.java", "junit/src/org/chromium/chrome/browser/tasks/JourneyManagerTest.java",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java index 4f4cdfb..9e0cb8f 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
@@ -16,6 +16,7 @@ import android.widget.ScrollView; import org.chromium.base.ObserverList; +import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.chrome.autofill_assistant.R; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantActionsCarouselCoordinator; @@ -30,12 +31,12 @@ import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataCoordinator; import org.chromium.chrome.browser.autofill_assistant.user_data.AssistantCollectUserDataModel; import org.chromium.chrome.browser.compositor.CompositorViewResizer; -import org.chromium.chrome.browser.tab.TabViewAndroidDelegate; import org.chromium.chrome.browser.ui.TabObscuringHandler; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContent; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver; import org.chromium.content_public.browser.WebContents; +import org.chromium.ui.base.ApplicationViewportInsetSupplier; /** * Coordinator responsible for the Autofill Assistant bottom bar. @@ -53,6 +54,7 @@ private final AssistantRootViewContainer mRootViewContainer; @Nullable private WebContents mWebContents; + private ApplicationViewportInsetSupplier mWindowApplicationInsetSupplier; // Child coordinators. private final AssistantHeaderCoordinator mHeaderCoordinator; @@ -60,6 +62,7 @@ private final AssistantFormCoordinator mFormCoordinator; private final AssistantActionsCarouselCoordinator mActionsCoordinator; private final AssistantPeekHeightCoordinator mPeekHeightCoordinator; + private final ObservableSupplierImpl<Integer> mInsetSupplier = new ObservableSupplierImpl<>(); private AssistantInfoBoxCoordinator mInfoBoxCoordinator; private AssistantCollectUserDataCoordinator mPaymentRequestCoordinator; private final AssistantGenericUiCoordinator mGenericUiCoordinator; @@ -84,6 +87,10 @@ mModel = model; mBottomSheetController = controller; + mWindowApplicationInsetSupplier = + activity.getWindowAndroid().getApplicationBottomInsetProvider(); + mWindowApplicationInsetSupplier.addSupplier(mInsetSupplier); + BottomSheetContent currentSheetContent = controller.getCurrentSheetContent(); if (currentSheetContent instanceof AssistantBottomSheetContent) { mContent = (AssistantBottomSheetContent) currentSheetContent; @@ -262,6 +269,7 @@ */ public void destroy() { resetVisualViewportHeight(); + mWindowApplicationInsetSupplier.removeSupplier(mInsetSupplier); mInfoBoxCoordinator.destroy(); mInfoBoxCoordinator = null; @@ -396,10 +404,7 @@ } mLastVisualViewportResizing = resizing; - TabViewAndroidDelegate chromeDelegate = - (TabViewAndroidDelegate) mWebContents.getViewAndroidDelegate(); - assert chromeDelegate != null; - chromeDelegate.insetViewportBottom(resizing); + mInsetSupplier.set(resizing); } // Implementation of methods from AutofillAssistantSizeManager.
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantGenericUiDelegate.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantGenericUiDelegate.java index 3907687..17be058 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantGenericUiDelegate.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantGenericUiDelegate.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.autofill_assistant.generic_ui; +import android.support.annotation.Nullable; + import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; @@ -28,11 +30,13 @@ mNativeAssistantGenericUiDelegate, AssistantGenericUiDelegate.this, identifier); } - void onListPopupSelectionChanged(String identifier, AssistantValue value) { + void onListPopupSelectionChanged(String selectedIndicesIdentifier, + AssistantValue selectedIndices, @Nullable String selectedNamesIdentifier, + @Nullable AssistantValue selectedNames) { assert mNativeAssistantGenericUiDelegate != 0; AssistantGenericUiDelegateJni.get().onListPopupSelectionChanged( - mNativeAssistantGenericUiDelegate, AssistantGenericUiDelegate.this, identifier, - value); + mNativeAssistantGenericUiDelegate, AssistantGenericUiDelegate.this, + selectedIndicesIdentifier, selectedIndices, selectedNamesIdentifier, selectedNames); } void onCalendarPopupDateChanged(String identifier, AssistantValue value) { @@ -52,7 +56,9 @@ void onViewClicked(long nativeAssistantGenericUiDelegate, AssistantGenericUiDelegate caller, String identifier); void onListPopupSelectionChanged(long nativeAssistantGenericUiDelegate, - AssistantGenericUiDelegate caller, String identifier, AssistantValue value); + AssistantGenericUiDelegate caller, String selectedIndicesIdentifier, + AssistantValue selectedIndices, @Nullable String selectedNamesIdentifier, + @Nullable AssistantValue selectedNames); void onCalendarPopupDateChanged(long nativeAssistantGenericUiDelegate, AssistantGenericUiDelegate caller, String identifier, AssistantValue value); }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java index 982e2d5..129d38f 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java
@@ -9,6 +9,7 @@ import android.content.Context; import android.support.annotation.Nullable; import android.view.View; +import android.widget.TextView; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; @@ -34,18 +35,26 @@ @CalledByNative private static void showListPopup(Context context, String[] itemNames, @PopupItemType int[] itemTypes, int[] selectedItems, boolean multiple, - String identifier, AssistantGenericUiDelegate delegate) { + String selectedIndicesIdentifier, @Nullable String selectedNamesIdentifier, + AssistantGenericUiDelegate delegate) { assert (itemNames.length == itemTypes.length); List<SelectPopupItem> popupItems = new ArrayList<>(); for (int i = 0; i < itemNames.length; i++) { popupItems.add(new SelectPopupItem(itemNames[i], itemTypes[i])); } - SelectPopupDialog dialog = new SelectPopupDialog(context, - (indices) - -> delegate.onListPopupSelectionChanged( - identifier, new AssistantValue(indices)), - popupItems, multiple, selectedItems); + SelectPopupDialog dialog = new SelectPopupDialog(context, (indices) -> { + AssistantValue selectedNamesValue = null; + if (selectedNamesIdentifier != null) { + String[] selectedNames = new String[indices != null ? indices.length : 0]; + for (int i = 0; i < selectedNames.length; ++i) { + selectedNames[i] = itemNames[indices[i]]; + } + selectedNamesValue = new AssistantValue(selectedNames); + } + delegate.onListPopupSelectionChanged(selectedIndicesIdentifier, + new AssistantValue(indices), selectedNamesIdentifier, selectedNamesValue); + }, popupItems, multiple, selectedItems); dialog.show(); } @@ -85,4 +94,13 @@ maxDate.getDateTimes().get(0).getTimeInUtcMillis(), -1, null); return true; } + + @CalledByNative + private static boolean setTextViewText(View view, String text) { + if (!(view instanceof TextView)) { + return false; + } + ((TextView) view).setText(text); + return true; + } }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java index ec4aeb4..efacc2d4 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java
@@ -53,6 +53,7 @@ import org.chromium.chrome.browser.autofill_assistant.proto.CollectUserDataResultProto; import org.chromium.chrome.browser.autofill_assistant.proto.ColorProto; import org.chromium.chrome.browser.autofill_assistant.proto.ComputeValueProto; +import org.chromium.chrome.browser.autofill_assistant.proto.DateFormatProto; import org.chromium.chrome.browser.autofill_assistant.proto.DateList; import org.chromium.chrome.browser.autofill_assistant.proto.DateProto; import org.chromium.chrome.browser.autofill_assistant.proto.DividerViewProto; @@ -74,6 +75,7 @@ import org.chromium.chrome.browser.autofill_assistant.proto.ProcessedActionStatusProto; import org.chromium.chrome.browser.autofill_assistant.proto.PromptProto; import org.chromium.chrome.browser.autofill_assistant.proto.SetModelValueProto; +import org.chromium.chrome.browser.autofill_assistant.proto.SetTextProto; import org.chromium.chrome.browser.autofill_assistant.proto.SetUserActionsProto; import org.chromium.chrome.browser.autofill_assistant.proto.ShapeDrawableProto; import org.chromium.chrome.browser.autofill_assistant.proto.ShowCalendarPopupProto; @@ -84,6 +86,7 @@ import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto; import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto; import org.chromium.chrome.browser.autofill_assistant.proto.TextViewProto; +import org.chromium.chrome.browser.autofill_assistant.proto.ToStringProto; import org.chromium.chrome.browser.autofill_assistant.proto.UserActionList; import org.chromium.chrome.browser.autofill_assistant.proto.UserActionProto; import org.chromium.chrome.browser.autofill_assistant.proto.ValueProto; @@ -641,36 +644,54 @@ @MediumTest @DisableIf.Build(sdk_is_less_than = 21) public void testListPopup() { - ViewProto clickableView = (ViewProto) ViewProto.newBuilder() - .setTextView(TextViewProto.newBuilder().setText( - "Shows a list popup when clicked")) - .setIdentifier("clickableView") - .build(); - - ViewProto rootView = - (ViewProto) ViewProto.newBuilder() - .setViewContainer( - ViewContainerProto.newBuilder() - .setLinearLayout( - LinearLayoutProto.newBuilder().setOrientation( - LinearLayoutProto.Orientation.VERTICAL)) - .addViews(clickableView)) - .build(); - List<InteractionProto> interactions = new ArrayList<>(); + interactions.add( + (InteractionProto) InteractionProto.newBuilder() + .setTriggerEvent(EventProto.newBuilder().setOnValueChanged( + OnModelValueChangedEventProto.newBuilder().setModelIdentifier( + "chips"))) + .addCallbacks(CallbackProto.newBuilder().setSetUserActions( + SetUserActionsProto.newBuilder().setModelIdentifier("chips"))) + .build()); interactions.add((InteractionProto) InteractionProto.newBuilder() - .setTriggerEvent(EventProto.newBuilder().setOnViewClicked( - OnViewClickedEventProto.newBuilder().setViewIdentifier( - "clickableView"))) - .addCallbacks(CallbackProto.newBuilder().setShowListPopup( - ShowListPopupProto.newBuilder() - .setItemNamesModelIdentifier("items") - .setSelectedItemIndicesModelIdentifier( - "selected_items_indices") - .setAllowMultiselect(false))) + .setTriggerEvent(EventProto.newBuilder().setOnUserActionCalled( + OnUserActionCalled.newBuilder().setUserActionIdentifier( + "done_chip"))) + .addCallbacks(CallbackProto.newBuilder().setEndAction( + EndActionProto.newBuilder().setStatus( + ProcessedActionStatusProto.ACTION_APPLIED))) .build()); + interactions.add( + (InteractionProto) InteractionProto.newBuilder() + .setTriggerEvent(EventProto.newBuilder().setOnViewClicked( + OnViewClickedEventProto.newBuilder().setViewIdentifier( + "clickableView"))) + .addCallbacks(CallbackProto.newBuilder().setShowListPopup( + ShowListPopupProto.newBuilder() + .setItemNamesModelIdentifier("items") + .setSelectedItemIndicesModelIdentifier( + "selected_items_indices") + .setSelectedItemNamesModelIdentifier("selected_item_names") + .setAllowMultiselect(false))) + .build()); List<ModelProto.ModelValue> modelValues = new ArrayList<>(); + modelValues.add((ModelProto.ModelValue) ModelProto.ModelValue.newBuilder() + .setIdentifier("value_a") + .setValue(ValueProto.newBuilder().setInts( + IntList.newBuilder().addValues(1))) + .build()); + modelValues.add( + (ModelProto.ModelValue) ModelProto.ModelValue.newBuilder() + .setIdentifier("chips") + .setValue(ValueProto.newBuilder().setUserActions( + UserActionList.newBuilder().addValues( + UserActionProto.newBuilder() + .setChip(ChipProto.newBuilder() + .setText("Done") + .setType(ChipType.NORMAL_ACTION)) + .setIdentifier("done_chip")))) + .build()); modelValues.add( (ModelProto.ModelValue) ModelProto.ModelValue.newBuilder() .setIdentifier("items") @@ -681,22 +702,28 @@ modelValues.add((ModelProto.ModelValue) ModelProto.ModelValue.newBuilder() .setIdentifier("selected_items_indices") .build()); + modelValues.add((ModelProto.ModelValue) ModelProto.ModelValue.newBuilder() + .setIdentifier("selected_item_names") + .build()); + + GenericUserInterfaceProto genericUserInterface = + (GenericUserInterfaceProto) GenericUserInterfaceProto.newBuilder() + .setRootView(ViewProto.newBuilder() + .setTextView(TextViewProto.newBuilder().setText( + "Shows a list popup when clicked")) + .setIdentifier("clickableView")) + .setInteractions( + InteractionsProto.newBuilder().addAllInteractions(interactions)) + .setModel(ModelProto.newBuilder().addAllValues(modelValues)) + .build(); ArrayList<ActionProto> list = new ArrayList<>(); list.add((ActionProto) ActionProto.newBuilder() - .setCollectUserData( - CollectUserDataProto.newBuilder() - .setGenericUserInterfacePrepended( - GenericUserInterfaceProto.newBuilder() - .setRootView(rootView) - .setInteractions( - InteractionsProto.newBuilder() - .addAllInteractions( - interactions)) - .setModel(ModelProto.newBuilder() - .addAllValues( - modelValues))) - .setRequestTermsAndConditions(false)) + .setShowGenericUi( + ShowGenericUiProto.newBuilder() + .setGenericUserInterface(genericUserInterface) + .addAllOutputModelIdentifiers(Arrays.asList( + "selected_items_indices", "selected_item_names"))) .build()); AutofillAssistantTestScript script = new AutofillAssistantTestScript( (SupportedScriptProto) SupportedScriptProto.newBuilder() @@ -710,33 +737,20 @@ new AutofillAssistantTestService(Collections.singletonList(script)); startAutofillAssistant(mTestRule.getActivity(), testService); - waitUntilViewMatchesCondition(withText("Continue"), isCompletelyDisplayed()); + waitUntilViewMatchesCondition(withText("Done"), isCompletelyDisplayed()); onView(withText("Shows a list popup when clicked")).perform(click()); onView(withText("09:30 AM")).inRoot(isDialog()).perform(click()); - // Finish action, wait for response and prepare next set of actions. - List<ActionProto> nextActions = new ArrayList<>(); - nextActions.add( - (ActionProto) ActionProto.newBuilder() - .setPrompt(PromptProto.newBuilder() - .setMessage("Finished") - .addChoices(PromptProto.Choice.newBuilder().setChip( - ChipProto.newBuilder() - .setType(ChipType.DONE_ACTION) - .setText("End")))) - .build()); - testService.setNextActions(nextActions); - waitUntilViewMatchesCondition(withText("Continue"), isEnabled()); int numNextActionsCalled = testService.getNextActionsCounter(); - onView(withText("Continue")).perform(click()); + onView(withContentDescription("Done")).perform(click()); testService.waitUntilGetNextActions(numNextActionsCalled + 1); List<ProcessedActionProto> processedActions = testService.getProcessedActions(); assertThat(processedActions, iterableWithSize(1)); assertThat( processedActions.get(0).getStatus(), is(ProcessedActionStatusProto.ACTION_APPLIED)); - CollectUserDataResultProto result = processedActions.get(0).getCollectUserDataResult(); + ShowGenericUiProto.Result result = processedActions.get(0).getShowGenericUiResult(); List<ModelProto.ModelValue> resultModelValues = result.getModel().getValuesList(); assertThat(resultModelValues, iterableWithSize(2)); assertThat((ModelProto.ModelValue) ModelProto.ModelValue.newBuilder() @@ -745,6 +759,12 @@ IntList.newBuilder().addValues(3))) .build(), isIn(resultModelValues)); + assertThat((ModelProto.ModelValue) ModelProto.ModelValue.newBuilder() + .setIdentifier("selected_item_names") + .setValue(ValueProto.newBuilder().setStrings( + StringList.newBuilder().addValues("09:30 AM"))) + .build(), + isIn(resultModelValues)); } @Test @@ -1030,10 +1050,36 @@ .setMinDateModelIdentifier("min_date") .setMaxDateModelIdentifier("max_date"))) .build()); + interactions.add( + (InteractionProto) InteractionProto.newBuilder() + .setTriggerEvent(EventProto.newBuilder().setOnValueChanged( + OnModelValueChangedEventProto.newBuilder().setModelIdentifier( + "date"))) + .addCallbacks(CallbackProto.newBuilder().setComputeValue( + ComputeValueProto.newBuilder() + .setResultModelIdentifier("date_string") + .setToString( + ToStringProto.newBuilder() + .setModelIdentifier("date") + .setDateFormat( + DateFormatProto.newBuilder() + .setDateFormat( + "EEE, MMM d y"))))) + .build()); + interactions.add( + (InteractionProto) InteractionProto.newBuilder() + .setTriggerEvent(EventProto.newBuilder().setOnValueChanged( + OnModelValueChangedEventProto.newBuilder().setModelIdentifier( + "date_string"))) + .addCallbacks(CallbackProto.newBuilder().setSetText( + SetTextProto.newBuilder() + .setModelIdentifier("date_string") + .setViewIdentifier("text_view"))) + .build()); GenericUserInterfaceProto genericUserInterface = (GenericUserInterfaceProto) GenericUserInterfaceProto.newBuilder() - .setRootView(createTextView("Click me", "text_view")) + .setRootView(createTextView("", "text_view")) .setInteractions( InteractionsProto.newBuilder().addAllInteractions(interactions)) .setModel(ModelProto.newBuilder().addAllValues(modelValues)) @@ -1057,13 +1103,14 @@ new AutofillAssistantTestService(Collections.singletonList(script)); startAutofillAssistant(mTestRule.getActivity(), testService); - waitUntilViewMatchesCondition(withText("Done"), isCompletelyDisplayed()); + waitUntilViewMatchesCondition(withText("Wed, Apr 15, 2020"), isCompletelyDisplayed()); - onView(withText("Click me")).perform(click()); + onView(withText("Wed, Apr 15, 2020")).perform(click()); onView(withClassName(equalTo(DatePicker.class.getName()))) .inRoot(isDialog()) .perform(setDate(2020, 7, 13)); onView(withText(R.string.date_picker_dialog_set)).inRoot(isDialog()).perform(click()); + waitUntilViewMatchesCondition(withText("Mon, Jul 13, 2020"), isCompletelyDisplayed()); int numNextActionsCalled = testService.getNextActionsCounter(); onView(withContentDescription("Done")).perform(click());
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java index faafea5b..c763726 100644 --- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java +++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java
@@ -75,6 +75,7 @@ @Before public void setUp() { + setAutofillFeature(true); ShadowRecordHistogram.reset(); MockitoAnnotations.initMocks(this); mocker.mock(RecordHistogramJni.TEST_HOOKS, mMockRecordHistogramNatives);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorFieldModel.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorFieldModel.java index 8c2f9ce..c8181443 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorFieldModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorFieldModel.java
@@ -11,8 +11,8 @@ import androidx.annotation.Nullable; import org.chromium.base.Callback; -import org.chromium.base.ContextUtils; import org.chromium.chrome.browser.autofill.settings.AutofillProfileBridge.DropdownKeyValue; +import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import java.util.ArrayList; import java.util.HashMap; @@ -193,7 +193,8 @@ * Constructs a checkbox to show in the editor. It's checked by default. * * @param checkboxLabel The label for the checkbox. - * @param checkboxPreference The shared preference for the checkbox status. + * @param checkboxPreference The shared preference key for the checkbox status. It must be in + * ChromePreferenceKeys. */ public static EditorFieldModel createCheckbox( CharSequence checkboxLabel, CharSequence checkboxPreference) { @@ -388,16 +389,13 @@ /** @return Whether the checkbox is checked. */ public boolean isChecked() { assert mInputTypeHint == INPUT_TYPE_HINT_CHECKBOX; - return ContextUtils.getAppSharedPreferences().getBoolean(mValue.toString(), true); + return SharedPreferencesManager.getInstance().readBoolean(mValue.toString(), true); } /** Sets the checkbox state. */ public void setIsChecked(boolean isChecked) { assert mInputTypeHint == INPUT_TYPE_HINT_CHECKBOX; - ContextUtils.getAppSharedPreferences() - .edit() - .putBoolean(mValue.toString(), isChecked) - .apply(); + SharedPreferencesManager.getInstance().writeBoolean(mValue.toString(), isChecked); } /** @return The list of icons resource identifiers to display. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java index ee50aa6a..f807a51 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
@@ -276,10 +276,6 @@ if (tab == null) return null; TabAssociatedApp.from(tab).setAppId(mConnection.getClientPackageNameForSession(mSession)); - if (mIntentDataProvider.shouldEnableEmbeddedMediaExperience()) { - // Configures web preferences for viewing downloaded media. - if (tab.getWebContents() != null) tab.getWebContents().notifyRendererPreferenceUpdate(); - } initializeTab(tab); return tab; } @@ -378,10 +374,6 @@ TabAssociatedApp.from(tab).setAppId(mConnection.getClientPackageNameForSession(mSession)); - if (mIntentDataProvider.shouldEnableEmbeddedMediaExperience()) { - if (tab.getWebContents() != null) tab.getWebContents().notifyRendererPreferenceUpdate(); - } - initializeTab(tab); if (mIntentDataProvider.getTranslateLanguage() != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java index f3823e9..758f529 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java
@@ -121,6 +121,9 @@ */ void maybeAdjustInstantAppExtras(Intent intent, boolean isIntentToInstantApp); + /** Invoked for intents with user gestures and records the user gesture if desired. */ + void maybeSetUserGesture(Intent intent); + /** * Records the pending incognito URL if desired. Called only if the * navigation is occurring in the context of incognito mode.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java index 2fc190e..3f577a7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -599,6 +599,13 @@ } @Override + public void maybeSetUserGesture(Intent intent) { + // The intent can be used to launch Chrome itself, record the user + // gesture here so that it can be used later. + IntentWithGesturesHandler.getInstance().onNewIntentWithGesture(intent); + } + + @Override public void maybeSetPendingReferrer(Intent intent, String referrerUrl) { IntentHandler.setPendingReferrer(intent, referrerUrl); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java index 377ee98d..bd2bd0e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -26,9 +26,9 @@ import org.chromium.base.Log; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.components.embedder_support.util.UrlUtilities; +import org.chromium.components.external_intents.ExternalIntentsFeatureList; import org.chromium.components.external_intents.ExternalIntentsSwitches; import org.chromium.components.external_intents.ExternalNavigationParams; import org.chromium.components.external_intents.RedirectHandler; @@ -361,8 +361,8 @@ /** Wrapper of check against the feature to support overriding for testing. */ @VisibleForTesting boolean blockExternalFormRedirectsWithoutGesture() { - return ChromeFeatureList.isEnabled( - ChromeFeatureList.INTENT_BLOCK_EXTERNAL_FORM_REDIRECT_NO_GESTURE); + return ExternalIntentsFeatureList.isEnabled( + ExternalIntentsFeatureList.INTENT_BLOCK_EXTERNAL_FORM_REDIRECT_NO_GESTURE); } /** @@ -687,11 +687,7 @@ AiaIntent.SERP, AiaIntent.NUM_ENTRIES); } - // The intent can be used to launch Chrome itself, record the user - // gesture here so that it can be used later. - if (params.hasUserGesture()) { - IntentWithGesturesHandler.getInstance().onNewIntentWithGesture(targetIntent); - } + if (params.hasUserGesture()) mDelegate.maybeSetUserGesture(targetIntent); } private @OverrideUrlLoadingResult int handleExternalIncognitoIntent(Intent targetIntent,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java index 38bd1d18..4dabdd5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
@@ -30,6 +30,7 @@ import org.chromium.chrome.browser.autofill.prefeditor.EditorModel; import org.chromium.chrome.browser.autofill.settings.AutofillProfileBridge.DropdownKeyValue; import org.chromium.chrome.browser.payments.PaymentRequestImpl.PaymentRequestServiceObserverForTest; +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.components.payments.MethodStrings; import org.chromium.content_public.browser.WebContents; import org.chromium.payments.mojom.PaymentMethodData; @@ -92,9 +93,6 @@ /** The dropdown key that triggers the address editor to add a new billing address. */ private static final String BILLING_ADDRESS_ADD_NEW = "add"; - /** The shared preference for the 'save card to device' checkbox status. */ - private static final String CHECK_SAVE_CARD_TO_DEVICE = "check_save_card_to_device"; - /** The web contents where the web payments API is invoked. */ private final WebContents mWebContents; @@ -765,7 +763,7 @@ if (mSaveCardCheckbox == null) { mSaveCardCheckbox = EditorFieldModel.createCheckbox( mContext.getString(R.string.payments_save_card_to_device_checkbox), - CHECK_SAVE_CARD_TO_DEVICE); + ChromePreferenceKeys.PAYMENTS_CHECK_SAVE_CARD_TO_DEVICE); } editor.addField(mSaveCardCheckbox); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java index a8690c7..b779a7d4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java
@@ -6,6 +6,8 @@ import android.view.ViewGroup; +import org.chromium.base.Callback; +import org.chromium.base.supplier.ObservableSupplier; import org.chromium.content_public.browser.RenderWidgetHostView; import org.chromium.ui.base.ViewAndroidDelegate; @@ -21,9 +23,41 @@ */ private int mApplicationViewportInsetBottomPx; + /** The inset supplier the observer is currently attached to. */ + private ObservableSupplier<Integer> mCurrentInsetSupplier; + TabViewAndroidDelegate(Tab tab, ViewGroup containerView) { super(containerView); mTab = (TabImpl) tab; + + Callback<Integer> insetObserver = (inset) -> updateInsetViewportBottom(); + mCurrentInsetSupplier = tab.getWindowAndroid().getApplicationBottomInsetProvider(); + mCurrentInsetSupplier.addObserver(insetObserver); + + mTab.addObserver(new EmptyTabObserver() { + @Override + public void onActivityAttachmentChanged(Tab tab, boolean isAttached) { + if (isAttached) { + mCurrentInsetSupplier = + tab.getWindowAndroid().getApplicationBottomInsetProvider(); + mCurrentInsetSupplier.addObserver(insetObserver); + } else { + mCurrentInsetSupplier.removeObserver(insetObserver); + mCurrentInsetSupplier = null; + updateInsetViewportBottom(); + } + } + + @Override + public void onShown(Tab tab, int type) { + updateInsetViewportBottom(); + } + + @Override + public void onHidden(Tab tab, int reason) { + updateInsetViewportBottom(); + } + }); } @Override @@ -45,12 +79,14 @@ bottomControlsOffsetY, bottomControlsMinHeightOffsetY); } - /** - * Sets the Visual Viewport bottom inset. - * @param viewportInsetBottomPx The bottom inset in pixels. Use {@code 0} for no inset. - */ - public void insetViewportBottom(int viewportInsetBottomPx) { - mApplicationViewportInsetBottomPx = viewportInsetBottomPx; + /** Sets the Visual Viewport bottom inset. */ + private void updateInsetViewportBottom() { + int inset = + mTab.isHidden() || mCurrentInsetSupplier == null ? 0 : mCurrentInsetSupplier.get(); + + if (inset == mApplicationViewportInsetBottomPx) return; + + mApplicationViewportInsetBottomPx = inset; RenderWidgetHostView renderWidgetHostView = mTab.getWebContents().getRenderWidgetHostView(); if (renderWidgetHostView == null) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java index a72e4f8..9d1a5b15 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -5,13 +5,11 @@ package org.chromium.chrome.browser.webapps; import android.content.Intent; -import android.os.Bundle; import androidx.browser.trusted.sharing.ShareData; import org.chromium.base.IntentUtils; import org.chromium.chrome.browser.flags.ActivityType; -import org.chromium.content_public.browser.WebContents; import org.chromium.webapk.lib.common.WebApkConstants; /** @@ -32,13 +30,6 @@ } @Override - protected void initializeUI(Bundle savedInstance) { - super.initializeUI(savedInstance); - WebContents webContents = getActivityTab().getWebContents(); - if (webContents != null) webContents.notifyRendererPreferenceUpdate(); - } - - @Override public boolean shouldPreferLightweightFre(Intent intent) { // We cannot use getWebApkPackageName() because // {@link WebappActivity#performPreInflationStartup()} may not have been called yet.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkExtras.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkExtras.java index 30917de..e577f794 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkExtras.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkExtras.java
@@ -20,11 +20,6 @@ public final String webApkPackageName; /** - * Badge icon to use for notifications. - */ - public final WebappIcon badgeIcon; - - /** * Icon to use for the splash screen. */ public final WebappIcon splashIcon; @@ -101,7 +96,7 @@ } public static WebApkExtras createEmpty() { - return new WebApkExtras(null /* webApkPackageName */, new WebappIcon(), new WebappIcon(), + return new WebApkExtras(null /* webApkPackageName */, new WebappIcon(), false /* isSplashIconMaskable */, 0 /* shellApkVersion */, null /* manifestUrl */, null /* manifestStartUrl */, WebApkDistributor.OTHER, null /* iconUrlToMurmur2HashMap */, new ShareTarget(), @@ -109,14 +104,13 @@ 0 /* webApkVersionCode */); } - public WebApkExtras(String webApkPackageName, WebappIcon badgeIcon, WebappIcon splashIcon, + public WebApkExtras(String webApkPackageName, WebappIcon splashIcon, boolean isSplashIconMaskable, int shellApkVersion, String manifestUrl, String manifestStartUrl, @WebApkDistributor int distributor, Map<String, String> iconUrlToMurmur2HashMap, ShareTarget shareTarget, boolean isSplashProvidedByWebApk, List<ShortcutItem> shortcutItems, int webApkVersionCode) { this.webApkPackageName = webApkPackageName; - this.badgeIcon = badgeIcon; this.splashIcon = splashIcon; this.isSplashIconMaskable = isSplashIconMaskable; this.shellApkVersion = shellApkVersion;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java index cea06b7..6408c0a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
@@ -134,7 +134,6 @@ * @param url URL that the WebAPK should navigate to when launched. * @param scope Scope for the WebAPK. * @param primaryIcon Primary icon to show for the WebAPK. - * @param badgeIcon Badge icon to use for notifications. * @param splashIcon Splash icon to use for the splash screen. * @param name Name of the WebAPK. * @param shortName The short name of the WebAPK. @@ -165,21 +164,20 @@ * @param webApkVersionCode WebAPK's version code. */ public static WebApkInfo create(String url, String scope, WebappIcon primaryIcon, - WebappIcon badgeIcon, WebappIcon splashIcon, String name, String shortName, - @WebDisplayMode int displayMode, int orientation, int source, long themeColor, - long backgroundColor, int defaultBackgroundColor, boolean isPrimaryIconMaskable, - boolean isSplashIconMaskable, String webApkPackageName, int shellApkVersion, - String manifestUrl, String manifestStartUrl, @WebApkDistributor int distributor, + WebappIcon splashIcon, String name, String shortName, @WebDisplayMode int displayMode, + int orientation, int source, long themeColor, long backgroundColor, + int defaultBackgroundColor, boolean isPrimaryIconMaskable, boolean isSplashIconMaskable, + String webApkPackageName, int shellApkVersion, String manifestUrl, + String manifestStartUrl, @WebApkDistributor int distributor, Map<String, String> iconUrlToMurmur2HashMap, ShareTarget shareTarget, boolean forceNavigation, boolean isSplashProvidedByWebApk, ShareData shareData, List<ShortcutItem> shortcutItems, int webApkVersionCode) { - return create(WebApkIntentDataProviderFactory.create(url, scope, primaryIcon, badgeIcon, - splashIcon, name, shortName, displayMode, orientation, source, themeColor, - backgroundColor, defaultBackgroundColor, isPrimaryIconMaskable, - isSplashIconMaskable, webApkPackageName, shellApkVersion, manifestUrl, - manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget, - forceNavigation, isSplashProvidedByWebApk, shareData, shortcutItems, - webApkVersionCode)); + return create(WebApkIntentDataProviderFactory.create(url, scope, primaryIcon, splashIcon, + name, shortName, displayMode, orientation, source, themeColor, backgroundColor, + defaultBackgroundColor, isPrimaryIconMaskable, isSplashIconMaskable, + webApkPackageName, shellApkVersion, manifestUrl, manifestStartUrl, distributor, + iconUrlToMurmur2HashMap, shareTarget, forceNavigation, isSplashProvidedByWebApk, + shareData, shortcutItems, webApkVersionCode)); } private static WebApkInfo create(@Nullable BrowserServicesIntentDataProvider provider) { @@ -191,13 +189,6 @@ } /** - * Returns the badge icon in Bitmap form. - */ - public WebappIcon badgeIcon() { - return getWebApkExtras().badgeIcon; - } - - /** * Returns the splash icon in Bitmap form. */ public WebappIcon splashIcon() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProviderFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProviderFactory.java index 4382a63..cfd1dacc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProviderFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProviderFactory.java
@@ -296,7 +296,6 @@ boolean isPrimaryIconMaskable = primaryMaskableIconId != 0 && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O); - int badgeIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.BADGE_ICON_ID, 0); int splashIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.SPLASH_ID, 0); int isSplashIconMaskableBooleanId = IntentUtils.safeGetInt( @@ -324,7 +323,6 @@ return create(url, scope, new WebappIcon(webApkPackageName, isPrimaryIconMaskable ? primaryMaskableIconId : primaryIconId), - new WebappIcon(webApkPackageName, badgeIconId), new WebappIcon(webApkPackageName, splashIconId), name, shortName, displayMode, orientation, source, themeColor, backgroundColor, defaultBackgroundColor, isPrimaryIconMaskable, isSplashIconMaskable, webApkPackageName, shellApkVersion, @@ -338,7 +336,6 @@ * @param url URL that the WebAPK should navigate to when launched. * @param scope Scope for the WebAPK. * @param primaryIcon Primary icon to show for the WebAPK. - * @param badgeIcon Badge icon to use for notifications. * @param splashIcon Splash icon to use for the splash screen. * @param name Name of the WebAPK. * @param shortName The short name of the WebAPK. @@ -371,14 +368,14 @@ * @param webApkVersionCode WebAPK's version code. */ public static BrowserServicesIntentDataProvider create(String url, String scope, - WebappIcon primaryIcon, WebappIcon badgeIcon, WebappIcon splashIcon, String name, - String shortName, @WebDisplayMode int displayMode, int orientation, int source, - long themeColor, long backgroundColor, int defaultBackgroundColor, - boolean isPrimaryIconMaskable, boolean isSplashIconMaskable, String webApkPackageName, - int shellApkVersion, String manifestUrl, String manifestStartUrl, - @WebApkDistributor int distributor, Map<String, String> iconUrlToMurmur2HashMap, - ShareTarget shareTarget, boolean forceNavigation, boolean isSplashProvidedByWebApk, - ShareData shareData, List<ShortcutItem> shortcutItems, int webApkVersionCode) { + WebappIcon primaryIcon, WebappIcon splashIcon, String name, String shortName, + @WebDisplayMode int displayMode, int orientation, int source, long themeColor, + long backgroundColor, int defaultBackgroundColor, boolean isPrimaryIconMaskable, + boolean isSplashIconMaskable, String webApkPackageName, int shellApkVersion, + String manifestUrl, String manifestStartUrl, @WebApkDistributor int distributor, + Map<String, String> iconUrlToMurmur2HashMap, ShareTarget shareTarget, + boolean forceNavigation, boolean isSplashProvidedByWebApk, ShareData shareData, + List<ShortcutItem> shortcutItems, int webApkVersionCode) { if (manifestStartUrl == null || webApkPackageName == null) { Log.e(TAG, "Incomplete data provided: " + manifestStartUrl + ", " + webApkPackageName); return null; @@ -399,10 +396,6 @@ primaryIcon = new WebappIcon(); } - if (badgeIcon == null) { - badgeIcon = new WebappIcon(); - } - if (splashIcon == null) { splashIcon = new WebappIcon(); } @@ -416,7 +409,7 @@ shortName, displayMode, orientation, source, WebappIntentUtils.colorFromLongColor(backgroundColor), defaultBackgroundColor, false /* isIconGenerated */, isPrimaryIconMaskable, forceNavigation); - WebApkExtras webApkExtras = new WebApkExtras(webApkPackageName, badgeIcon, splashIcon, + WebApkExtras webApkExtras = new WebApkExtras(webApkPackageName, splashIcon, isSplashIconMaskable, shellApkVersion, manifestUrl, manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget, isSplashProvidedByWebApk, shortcutItems, webApkVersionCode);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java index 3220fe9..7f662dd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java
@@ -141,10 +141,9 @@ int defaultBackgroundColor = SplashLayout.getDefaultBackgroundColor(appContext); WebApkInfo info = WebApkInfo.create(mOldInfo.url(), scopeUrl, - new WebappIcon(primaryIconBitmap), null /* badgeIcon*/, - new WebappIcon(splashIconBitmap), name, shortName, displayMode, orientation, - mOldInfo.source(), themeColor, backgroundColor, defaultBackgroundColor, - isPrimaryIconMaskable, false /* isSplashIconMaskable */, + new WebappIcon(primaryIconBitmap), new WebappIcon(splashIconBitmap), name, + shortName, displayMode, orientation, mOldInfo.source(), themeColor, backgroundColor, + defaultBackgroundColor, isPrimaryIconMaskable, false /* isSplashIconMaskable */, mOldInfo.webApkPackageName(), mOldInfo.shellApkVersion(), mOldInfo.manifestUrl(), manifestStartUrl, WebApkDistributor.BROWSER, iconUrlToMurmur2HashMap, shareTarget, mOldInfo.shouldForceNavigation(), mOldInfo.isSplashProvidedByWebApk(), null,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java index 03900b1..a89df8a9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java
@@ -336,6 +336,20 @@ @Test @SmallTest + public void testMaybeSetUserGesture() { + ExternalNavigationDelegateImpl delegate = new ExternalNavigationDelegateImpl( + mActivityTestRule.getActivity().getActivityTab()); + + String url = "http://www.example.com"; + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(url)); + + delegate.maybeSetUserGesture(intent); + Assert.assertTrue(IntentWithGesturesHandler.getInstance().getUserGestureAndClear(intent)); + } + + @Test + @SmallTest public void testMaybeSetPendingReferrer() { ExternalNavigationDelegateImpl delegate = new ExternalNavigationDelegateImpl( mActivityTestRule.getActivity().getActivityTab());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java index 5051cd8..d20063e5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -1548,8 +1548,7 @@ .withHasUserGesture(true) .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT, START_OTHER_ACTIVITY); - Assert.assertTrue(IntentWithGesturesHandler.getInstance().getUserGestureAndClear( - mDelegate.startActivityIntent)); + Assert.assertTrue(mDelegate.maybeSetUserGestureCalled); Assert.assertFalse(mDelegate.startIncognitoIntentCalled); } @@ -1565,8 +1564,7 @@ .withIsIncognito(true) .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_ASYNC_ACTION, START_INCOGNITO | START_OTHER_ACTIVITY); - Assert.assertTrue(IntentWithGesturesHandler.getInstance().getUserGestureAndClear( - mDelegate.startActivityIntent)); + Assert.assertTrue(mDelegate.maybeSetUserGestureCalled); Assert.assertTrue(mDelegate.startIncognitoIntentCalled); } @@ -1867,6 +1865,11 @@ } @Override + public void maybeSetUserGesture(Intent intent) { + maybeSetUserGestureCalled = true; + } + + @Override public void maybeSetPendingIncognitoUrl(Intent intent) {} @Override @@ -1991,6 +1994,7 @@ public Intent startActivityIntent; public boolean startIncognitoIntentCalled; + public boolean maybeSetUserGestureCalled; public boolean startFileIntentCalled; public String defaultSmsPackageName;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java index 0f7e961..4ac7a17a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
@@ -176,7 +176,7 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(WEBAPK_ID); - WebApkInfo info = WebApkInfo.create("", creationData.scope, null, null, null, + WebApkInfo info = WebApkInfo.create("", creationData.scope, null, null, creationData.name, creationData.shortName, creationData.displayMode, creationData.orientation, 0, creationData.themeColor, creationData.backgroundColor, 0, creationData.isPrimaryIconMaskable,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegateTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegateTest.java new file mode 100644 index 0000000..bab279e --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegateTest.java
@@ -0,0 +1,101 @@ +// Copyright 2020 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.tab; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.view.ViewGroup; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import org.chromium.base.supplier.ObservableSupplierImpl; +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.content_public.browser.WebContents; +import org.chromium.ui.base.ApplicationViewportInsetSupplier; +import org.chromium.ui.base.WindowAndroid; + +/** Unit tests for the TabViewAndroidDelegate. */ +@RunWith(BaseRobolectricTestRunner.class) +public class TabViewAndroidDelegateTest { + private final ArgumentCaptor<TabObserver> mTabObserverCaptor = + ArgumentCaptor.forClass(TabObserver.class); + + @Mock + private TabImpl mTab; + + @Mock + private WebContents mWebContents; + + @Mock + private WindowAndroid mWindowAndroid; + + @Mock + private ViewGroup mViewContainer; + + private ApplicationViewportInsetSupplier mApplicationInsetSupplier; + private ObservableSupplierImpl<Integer> mFeatureInsetSupplier; + private TabViewAndroidDelegate mViewAndroidDelegate; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mFeatureInsetSupplier = new ObservableSupplierImpl<>(); + + mApplicationInsetSupplier = ApplicationViewportInsetSupplier.createForTests(); + mApplicationInsetSupplier.addSupplier(mFeatureInsetSupplier); + + when(mWindowAndroid.getApplicationBottomInsetProvider()) + .thenReturn(mApplicationInsetSupplier); + when(mTab.getWindowAndroid()).thenReturn(mWindowAndroid); + when(mTab.getWebContents()).thenReturn(mWebContents); + + mViewAndroidDelegate = new TabViewAndroidDelegate(mTab, mViewContainer); + verify(mTab).addObserver(mTabObserverCaptor.capture()); + } + + @Test + public void testInset() { + mFeatureInsetSupplier.set(10); + assertEquals("The bottom inset for the tab should be non-zero.", 10, + mViewAndroidDelegate.getViewportInsetBottom()); + } + + @Test + public void testInset_afterHidden() { + mFeatureInsetSupplier.set(10); + + when(mTab.isHidden()).thenReturn(true); + + mTabObserverCaptor.getValue().onHidden(mTab, 0); + assertEquals("The bottom inset for the tab should be zero.", 0, + mViewAndroidDelegate.getViewportInsetBottom()); + } + + @Test + public void testInset_afterDetachAndAttach() { + mFeatureInsetSupplier.set(10); + + assertEquals("The bottom inset for the tab should be non-zero.", 10, + mViewAndroidDelegate.getViewportInsetBottom()); + + mTabObserverCaptor.getValue().onActivityAttachmentChanged(mTab, false); + + assertEquals("The bottom inset for the tab should be zero.", 0, + mViewAndroidDelegate.getViewportInsetBottom()); + + mTabObserverCaptor.getValue().onActivityAttachmentChanged(mTab, true); + + assertEquals("The bottom inset for the tab should be non-zero.", 10, + mViewAndroidDelegate.getViewportInsetBottom()); + } +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInfoTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInfoTest.java index 583a07d..826d37a 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInfoTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkInfoTest.java
@@ -249,7 +249,6 @@ Assert.assertEquals(PRIMARY_MASKABLE_ICON_ID, info.icon().resourceIdForTesting()); Assert.assertEquals(true, info.isIconAdaptive()); - Assert.assertEquals(null, info.badgeIcon().bitmap()); Assert.assertEquals(null, info.splashIcon().bitmap()); WebApkInfo.ShareTarget shareTarget = info.shareTarget();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java index 19e9d30e..7536f415 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
@@ -86,8 +86,6 @@ private static final String SHORT_NAME = "Short Name"; private static final String PRIMARY_ICON_URL = "/icon.png"; private static final String PRIMARY_ICON_MURMUR2_HASH = "3"; - private static final String BADGE_ICON_URL = "/badge.png"; - private static final String BADGE_ICON_MURMUR2_HASH = "4"; private static final @WebDisplayMode int DISPLAY_MODE = WebDisplayMode.UNDEFINED; private static final int ORIENTATION = ScreenOrientationValues.DEFAULT; private static final long THEME_COLOR = 1L; @@ -131,8 +129,8 @@ @Override public void storeWebApkUpdateRequestToFile(String updateRequestPath, String startUrl, String scope, String name, String shortName, String primaryIconUrl, - Bitmap primaryIcon, boolean isPrimaryIconMaskable, String badgeIconUrl, - Bitmap badgeIcon, String[] iconUrls, String[] iconHashes, + Bitmap primaryIcon, boolean isPrimaryIconMaskable, String splashIconUrl, + Bitmap splashIcon, String[] iconUrls, String[] iconHashes, @WebDisplayMode int displayMode, int orientation, long themeColor, long backgroundColor, String shareTargetAction, String shareTargetParamTitle, String shareTargetParamText, boolean shareTargetParamIsMethodPost, @@ -207,7 +205,7 @@ @Override protected void storeWebApkUpdateRequestToFile(String updateRequestPath, WebApkInfo info, - String primaryIconUrl, String badgeIconUrl, boolean isManifestStale, + String primaryIconUrl, String splashIconUrl, boolean isManifestStale, @WebApkUpdateReason int updateReason, Callback<Boolean> callback) { mStoreUpdateRequestCallback = callback; mUpdateName = info.name(); @@ -229,8 +227,6 @@ public Map<String, String> iconUrlToMurmur2HashMap; public String primaryIconUrl; public Bitmap primaryIcon; - public String badgeIconUrl; - public Bitmap badgeIcon; public @WebDisplayMode int displayMode; public int orientation; public long themeColor; @@ -355,12 +351,9 @@ manifestData.iconUrlToMurmur2HashMap = new HashMap<>(); manifestData.iconUrlToMurmur2HashMap.put(PRIMARY_ICON_URL, PRIMARY_ICON_MURMUR2_HASH); - manifestData.iconUrlToMurmur2HashMap.put(BADGE_ICON_URL, BADGE_ICON_MURMUR2_HASH); manifestData.primaryIconUrl = PRIMARY_ICON_URL; manifestData.primaryIcon = createBitmap(Color.GREEN); - manifestData.badgeIconUrl = BADGE_ICON_URL; - manifestData.badgeIcon = createBitmap(Color.BLUE); manifestData.displayMode = DISPLAY_MODE; manifestData.orientation = ORIENTATION; manifestData.themeColor = THEME_COLOR; @@ -383,9 +376,9 @@ final String kPackageName = "org.random.webapk"; return WebApkInfo.create("", manifestData.scopeUrl, - new WebappIcon(manifestData.primaryIcon), new WebappIcon(manifestData.badgeIcon), - null, manifestData.name, manifestData.shortName, manifestData.displayMode, - manifestData.orientation, -1, manifestData.themeColor, manifestData.backgroundColor, + new WebappIcon(manifestData.primaryIcon), null, manifestData.name, + manifestData.shortName, manifestData.displayMode, manifestData.orientation, -1, + manifestData.themeColor, manifestData.backgroundColor, manifestData.defaultBackgroundColor, false /* isPrimaryIconMaskable */, false /* isSplashIconMaskable*/, kPackageName, -1, WEB_MANIFEST_URL, manifestData.startUrl, WebApkDistributor.BROWSER, @@ -443,9 +436,9 @@ private static void onGotManifestData( WebApkUpdateManager updateManager, ManifestData fetchedManifestData) { String primaryIconUrl = randomIconUrl(fetchedManifestData); - String badgeIconUrl = randomIconUrl(fetchedManifestData); + String splashIconUrl = randomIconUrl(fetchedManifestData); updateManager.onGotManifestData( - infoFromManifestData(fetchedManifestData), primaryIconUrl, badgeIconUrl); + infoFromManifestData(fetchedManifestData), primaryIconUrl, splashIconUrl); } /** @@ -501,7 +494,7 @@ updateIfNeeded(WEBAPK_PACKAGE_NAME, updateManager, androidManifestData.shortcuts); assertTrue(updateManager.updateCheckStarted()); updateManager.onGotManifestData(infoFromManifestData(fetchedManifestData), - fetchedManifestData.primaryIconUrl, fetchedManifestData.badgeIconUrl); + fetchedManifestData.primaryIconUrl, null); return updateManager.updateRequested(); } @@ -964,20 +957,6 @@ /** * Test that an upgrade is requested when: - * - WebAPK was generated using icon at {@link BADGE_ICON_URL} from Web Manifest. - * - Bitmap at {@link BADGE_ICON_URL} has changed. - */ - @Test - public void testBadgeIconChangeShouldUpgrade() { - ManifestData fetchedData = defaultManifestData(); - fetchedData.iconUrlToMurmur2HashMap.put( - fetchedData.badgeIconUrl, BADGE_ICON_MURMUR2_HASH + "1"); - fetchedData.badgeIcon = createBitmap(Color.GREEN); - assertTrue(checkUpdateNeededForFetchedManifest(defaultManifestData(), fetchedData)); - } - - /** - * Test that an upgrade is requested when: * - WebAPK is generated using icon at {@link PRIMARY_ICON_URL} from Web Manifest. * - A new icon URL is added to the Web Manifest. And InstallableManager selects the new icon as * the primary icon. @@ -991,20 +970,6 @@ } /** - * Test that an upgrade is requested when: - * - WebAPK is generated using icon at {@link BADGE_ICON_URL} from Web Manifest. - * - A new icon URL is added to the Web Manifest. And InstallableManager selects the new icon as - * the badge icon. - */ - @Test - public void testBadgeIconUrlChangeShouldUpgrade() { - ManifestData fetchedData = defaultManifestData(); - fetchedData.iconUrlToMurmur2HashMap.put("/badge2.png", "44"); - fetchedData.badgeIconUrl = "/badge2.png"; - assertTrue(checkUpdateNeededForFetchedManifest(defaultManifestData(), fetchedData)); - } - - /** * Test that an upgrade is not requested if: * - icon URL is added to the Web Manifest * AND @@ -1040,7 +1005,6 @@ ManifestData androidManifestData = defaultManifestData(); androidManifestData.primaryIconUrl = iconUrl1; - androidManifestData.badgeIconUrl = badgeUrl1; androidManifestData.iconUrlToMurmur2HashMap.clear(); androidManifestData.iconUrlToMurmur2HashMap.put(iconUrl1, hash1); androidManifestData.iconUrlToMurmur2HashMap.put(iconUrl2, hash2); @@ -1049,7 +1013,6 @@ ManifestData fetchedManifestData = defaultManifestData(); fetchedManifestData.primaryIconUrl = iconUrl2; - fetchedManifestData.badgeIconUrl = badgeUrl2; fetchedManifestData.iconUrlToMurmur2HashMap.clear(); fetchedManifestData.iconUrlToMurmur2HashMap.put(iconUrl1, null); fetchedManifestData.iconUrlToMurmur2HashMap.put(iconUrl2, hash2);
diff --git a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java index 7d12b09..db1368b 100644 --- a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java +++ b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
@@ -34,7 +34,6 @@ "org.chromium.webapk.shell_apk.iconUrlsAndIconMurmur2Hashes"; public static final String WEB_MANIFEST_URL = "org.chromium.webapk.shell_apk.webManifestUrl"; public static final String DISTRIBUTOR = "org.chromium.webapk.shell_apk.distributor"; - public static final String BADGE_ICON_ID = "org.chromium.webapk.shell_apk.badgeIconId"; public static final String SHARE_ACTION = "org.chromium.webapk.shell_apk.shareAction"; public static final String SHARE_METHOD = "org.chromium.webapk.shell_apk.shareMethod"; public static final String SHARE_ENCTYPE = "org.chromium.webapk.shell_apk.shareEnctype";
diff --git a/chrome/android/webapk/shell_apk/AndroidManifest.xml b/chrome/android/webapk/shell_apk/AndroidManifest.xml index ad73ffcf..5e8efc1 100644 --- a/chrome/android/webapk/shell_apk/AndroidManifest.xml +++ b/chrome/android/webapk/shell_apk/AndroidManifest.xml
@@ -149,7 +149,6 @@ <meta-data android:name="org.chromium.webapk.shell_apk.iconUrlsAndIconMurmur2Hashes" android:value="{{{icon_urls_and_icon_murmur2_hashes}}}" /> <meta-data android:name="org.chromium.webapk.shell_apk.webManifestUrl" android:value="{{{web_manifest_url}}}" /> - {{#badge_icon_id}}<meta-data android:name="org.chromium.webapk.shell_apk.badgeIconId" android:resource="{{{badge_icon_id}}}" />{{/badge_icon_id}} <service android:name="org.chromium.webapk.shell_apk.WebApkServiceFactory" android:exported="true"
diff --git a/chrome/android/webapk/shell_apk/current_version/current_version.gni b/chrome/android/webapk/shell_apk/current_version/current_version.gni index 2504b26..5dfe743 100644 --- a/chrome/android/webapk/shell_apk/current_version/current_version.gni +++ b/chrome/android/webapk/shell_apk/current_version/current_version.gni
@@ -12,4 +12,4 @@ # //chrome/android/webapk/shell_apk:webapk is changed. This includes # Java files, Android resource files and AndroidManifest.xml. Does not affect # Chrome.apk -current_shell_apk_version = 122 +current_shell_apk_version = 124
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 0a877e9..b328704e 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2999,6 +2999,7 @@ "//components/crash/android:crash_android", "//components/embedder_support/android:util", "//components/embedder_support/android:web_contents_delegate", + "//components/external_intents/android", "//components/feed:buildflags", "//components/feed:feature_list", "//components/invalidation/impl:feature_list",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index 63cbb23..44c8186 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -98,6 +98,7 @@ "+components/embedder_support", "+components/encrypted_messages", "+components/exo", + "+components/external_intents", "+components/favicon_base", "+components/favicon/content", "+components/favicon/core",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 87f484ca..32071ea 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -177,6 +177,7 @@ #if defined(OS_ANDROID) #include "chrome/browser/android/explore_sites/explore_sites_feature.h" #include "chrome/browser/flags/android/chrome_feature_list.h" +#include "components/external_intents/android/external_intents_feature_list.h" #else // OS_ANDROID #include "chrome/browser/media/router/media_router_feature.h" #endif // OS_ANDROID @@ -4861,7 +4862,7 @@ flag_descriptions::kIntentBlockExternalFormRedirectsNoGestureDescription, kOsAndroid, FEATURE_VALUE_TYPE( - chrome::android::kIntentBlockExternalFormRedirectsNoGesture)}, + external_intents::kIntentBlockExternalFormRedirectsNoGesture)}, {"recover-from-never-save-android", flag_descriptions::kRecoverFromNeverSaveAndroidName, flag_descriptions::kRecoverFromNeverSaveAndroidDescription, kOsAndroid,
diff --git a/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc b/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc index d2b06395..946f8c3 100644 --- a/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc +++ b/chrome/browser/android/autofill_assistant/assistant_collect_user_data_delegate.cc
@@ -20,19 +20,6 @@ using base::android::AttachCurrentThread; using base::android::JavaParamRef; -namespace { -// Converts a java string to native. Returns an empty string if input is null. -std::string SafeConvertJavaStringToNative( - JNIEnv* env, - const base::android::JavaParamRef<jstring>& jstring) { - std::string native_string; - if (jstring) { - base::android::ConvertJavaStringToUTF8(env, jstring, &native_string); - } - return native_string; -} -} // namespace - namespace autofill_assistant { AssistantCollectUserDataDelegate::AssistantCollectUserDataDelegate( @@ -59,9 +46,14 @@ return; } - std::string name = SafeConvertJavaStringToNative(env, jpayer_name); - std::string phone = SafeConvertJavaStringToNative(env, jpayer_phone); - std::string email = SafeConvertJavaStringToNative(env, jpayer_email); + std::string name = ui_controller_android_utils::SafeConvertJavaStringToNative( + env, jpayer_name); + std::string phone = + ui_controller_android_utils::SafeConvertJavaStringToNative(env, + jpayer_phone); + std::string email = + ui_controller_android_utils::SafeConvertJavaStringToNative(env, + jpayer_email); auto contact_profile = std::make_unique<autofill::AutofillProfile>(); contact_profile->SetRawInfo(autofill::ServerFieldType::NAME_FULL, @@ -139,7 +131,9 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller, const base::android::JavaParamRef<jstring>& jidentifier) { - std::string identifier = SafeConvertJavaStringToNative(env, jidentifier); + std::string identifier = + ui_controller_android_utils::SafeConvertJavaStringToNative(env, + jidentifier); ui_controller_->OnLoginChoiceChanged(identifier); } @@ -205,7 +199,7 @@ const base::android::JavaParamRef<jstring>& jkey, const base::android::JavaParamRef<jobject>& jvalue) { ui_controller_->OnKeyValueChanged( - SafeConvertJavaStringToNative(env, jkey), + ui_controller_android_utils::SafeConvertJavaStringToNative(env, jkey), ui_controller_android_utils::ToNativeValue(env, jvalue)); }
diff --git a/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.cc b/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.cc index ec9924a..7637df3 100644 --- a/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.cc +++ b/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.cc
@@ -42,19 +42,20 @@ void AssistantGenericUiDelegate::OnListPopupSelectionChanged( JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller, - const base::android::JavaParamRef<jstring>& jmodel_identifier, - const base::android::JavaParamRef<jobject>& jvalue) { - std::string identifier; - if (jmodel_identifier) { - base::android::ConvertJavaStringToUTF8(env, jmodel_identifier, &identifier); + const base::android::JavaParamRef<jstring>& jindices_model_identifier, + const base::android::JavaParamRef<jobject>& jindicies_value, + const base::android::JavaParamRef<jstring>& jnames_model_identifier, + const base::android::JavaParamRef<jobject>& jnames_value) { + ui_controller_->OnValueChanged( + ui_controller_android_utils::SafeConvertJavaStringToNative( + env, jindices_model_identifier), + ui_controller_android_utils::ToNativeValue(env, jindicies_value)); + if (jnames_model_identifier) { + ui_controller_->OnValueChanged( + ui_controller_android_utils::SafeConvertJavaStringToNative( + env, jnames_model_identifier), + ui_controller_android_utils::ToNativeValue(env, jnames_value)); } - - ValueProto value; - if (jvalue) { - value = ui_controller_android_utils::ToNativeValue(env, jvalue); - } - - ui_controller_->OnValueChanged(identifier, value); } // TODO(b/145043394): refactor delegate methods into a single SetValue() where
diff --git a/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.h b/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.h index ff0aac40..03467f8 100644 --- a/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.h +++ b/chrome/browser/android/autofill_assistant/assistant_generic_ui_delegate.h
@@ -23,14 +23,17 @@ const base::android::JavaParamRef<jobject>& jcaller, const base::android::JavaParamRef<jstring>& jview_identifier); - // The selection in a list popup has changed. |jmodel_identifier| is the model - // identifier that the new selection indices should be written to. |jvalue| is - // a Java array of integers containing the newly selected indices. + // The selection in a list popup has changed. |jindices_model_identifier| is + // the model identifier that |jindicies_value| should be written to. + // |jnames_model_identifier| is the model identifier that |jnames_value| + // should be written to, if specified. void OnListPopupSelectionChanged( JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller, - const base::android::JavaParamRef<jstring>& jmodel_identifier, - const base::android::JavaParamRef<jobject>& jvalue); + const base::android::JavaParamRef<jstring>& jindices_model_identifier, + const base::android::JavaParamRef<jobject>& jindicies_value, + const base::android::JavaParamRef<jstring>& jnames_model_identifier, + const base::android::JavaParamRef<jobject>& jnames_value); // The date in a calendar popup has changed. |jmodel_identifier| is the model // identifier that the new date should be written to. |jvalue| is a Java
diff --git a/chrome/browser/android/autofill_assistant/generic_ui_controller_android.cc b/chrome/browser/android/autofill_assistant/generic_ui_controller_android.cc index a5f9d531f..7587d7c 100644 --- a/chrome/browser/android/autofill_assistant/generic_ui_controller_android.cc +++ b/chrome/browser/android/autofill_assistant/generic_ui_controller_android.cc
@@ -233,7 +233,7 @@ auto interaction_handler = std::make_unique<InteractionHandlerAndroid>(event_handler, jcontext); if (!interaction_handler->AddInteractionsFromProto( - proto.interactions(), env, *views, jdelegate, user_model, + proto.interactions(), env, views.get(), jdelegate, user_model, basic_interactions)) { return nullptr; }
diff --git a/chrome/browser/android/autofill_assistant/interaction_handler_android.cc b/chrome/browser/android/autofill_assistant/interaction_handler_android.cc index a07268a..966cf00 100644 --- a/chrome/browser/android/autofill_assistant/interaction_handler_android.cc +++ b/chrome/browser/android/autofill_assistant/interaction_handler_android.cc
@@ -129,9 +129,6 @@ } JNIEnv* env = base::android::AttachCurrentThread(); - auto jidentifier = base::android::ConvertUTF8ToJavaString( - env, proto.selected_item_indices_model_identifier()); - std::vector<std::string> item_names_vec; std::copy(item_names->strings().values().begin(), item_names->strings().values().end(), @@ -151,7 +148,14 @@ env, jcontext, base::android::ToJavaArrayOfStrings(env, item_names_vec), base::android::ToJavaIntArray(env, item_types_vec), base::android::ToJavaIntArray(env, selected_indices_vec), - proto.allow_multiselect(), jidentifier, jdelegate); + proto.allow_multiselect(), + base::android::ConvertUTF8ToJavaString( + env, proto.selected_item_indices_model_identifier()), + proto.selected_item_names_model_identifier().empty() + ? nullptr + : base::android::ConvertUTF8ToJavaString( + env, proto.selected_item_names_model_identifier()), + jdelegate); } void ShowCalendarPopup(base::WeakPtr<UserModel> user_model, @@ -202,19 +206,52 @@ } } +void SetTextViewText( + base::WeakPtr<UserModel> user_model, + const SetTextProto& proto, + std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>* views) { + if (!user_model) { + return; + } + + auto text = user_model->GetValue(proto.model_identifier()); + if (!text.has_value()) { + DVLOG(2) << "Failed to set text for " << proto.view_identifier() << ": " + << proto.model_identifier() << " not found in model"; + return; + } + if (text->strings().values_size() != 1) { + DVLOG(2) << "Failed to set text for " << proto.view_identifier() + << ": expected " << proto.model_identifier() + << " to contain single string, but was instead " << *text; + return; + } + + auto jview = views->find(proto.view_identifier()); + if (jview == views->end()) { + DVLOG(2) << "Failed to set text for " << proto.view_identifier() << ": " + << " view not found"; + return; + } + + JNIEnv* env = base::android::AttachCurrentThread(); + Java_AssistantViewInteractions_setTextViewText( + env, jview->second, + base::android::ConvertUTF8ToJavaString(env, text->strings().values(0))); +} + base::Optional<EventHandler::EventKey> CreateEventKeyFromProto( const EventProto& proto, JNIEnv* env, - const std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>& - views, + std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>* views, base::android::ScopedJavaGlobalRef<jobject> jdelegate) { switch (proto.kind_case()) { case EventProto::kOnValueChanged: return base::Optional<EventHandler::EventKey>( {proto.kind_case(), proto.on_value_changed().model_identifier()}); case EventProto::kOnViewClicked: { - auto jview = views.find(proto.on_view_clicked().view_identifier()); - if (jview == views.end()) { + auto jview = views->find(proto.on_view_clicked().view_identifier()); + if (jview == views->end()) { VLOG(1) << "Invalid click event, no view with id='" << proto.on_view_clicked().view_identifier() << "' found"; return base::nullopt; @@ -243,6 +280,7 @@ const CallbackProto& proto, UserModel* user_model, BasicInteractions* basic_interactions, + std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>* views, base::android::ScopedJavaGlobalRef<jobject> jcontext, base::android::ScopedJavaGlobalRef<jobject> jdelegate) { switch (proto.kind_case()) { @@ -310,7 +348,20 @@ base::BindRepeating(&ShowCalendarPopup, user_model->GetWeakPtr(), proto.show_calendar_popup(), jcontext, jdelegate)); - break; + case CallbackProto::kSetText: + if (proto.set_text().model_identifier().empty()) { + VLOG(1) << "Error creating SetText interaction: " + "model_identifier not set"; + return base::nullopt; + } + if (proto.set_text().view_identifier().empty()) { + VLOG(1) << "Error creating SetText interaction: " + "view_identifier not set"; + return base::nullopt; + } + return base::Optional<InteractionHandlerAndroid::InteractionCallback>( + base::BindRepeating(&SetTextViewText, user_model->GetWeakPtr(), + proto.set_text(), views)); case CallbackProto::KIND_NOT_SET: VLOG(1) << "Error creating interaction: kind not set"; return base::nullopt; @@ -344,8 +395,7 @@ bool InteractionHandlerAndroid::AddInteractionsFromProto( const InteractionsProto& proto, JNIEnv* env, - const std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>& - views, + std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>* views, base::android::ScopedJavaGlobalRef<jobject> jdelegate, UserModel* user_model, BasicInteractions* basic_interactions) { @@ -363,7 +413,8 @@ for (const auto& callback_proto : interaction_proto.callbacks()) { auto callback = CreateInteractionCallbackFromProto( - callback_proto, user_model, basic_interactions, jcontext_, jdelegate); + callback_proto, user_model, basic_interactions, views, jcontext_, + jdelegate); if (!callback) { VLOG(1) << "Invalid callback for interaction"; return false;
diff --git a/chrome/browser/android/autofill_assistant/interaction_handler_android.h b/chrome/browser/android/autofill_assistant/interaction_handler_android.h index 5239efe..115fc07 100644 --- a/chrome/browser/android/autofill_assistant/interaction_handler_android.h +++ b/chrome/browser/android/autofill_assistant/interaction_handler_android.h
@@ -43,11 +43,11 @@ // Creates callbacks for each interaction in |proto| as well as the // corresponding view events in |views|. Returns false if |proto| is invalid. + // |views| must outlive this interaction handler. bool AddInteractionsFromProto( const InteractionsProto& proto, JNIEnv* env, - const std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>& - views, + std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>>* views, base::android::ScopedJavaGlobalRef<jobject> jdelegate, UserModel* user_model, BasicInteractions* basic_interactions);
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android_utils.cc b/chrome/browser/android/autofill_assistant/ui_controller_android_utils.cc index 753854c9..fb0138a 100644 --- a/chrome/browser/android/autofill_assistant/ui_controller_android_utils.cc +++ b/chrome/browser/android/autofill_assistant/ui_controller_android_utils.cc
@@ -146,6 +146,9 @@ ValueProto ToNativeValue(JNIEnv* env, const base::android::JavaParamRef<jobject>& jvalue) { ValueProto proto; + if (!jvalue) { + return proto; + } auto jints = Java_AssistantValue_getIntegers(env, jvalue); if (jints) { auto* mutable_ints = proto.mutable_ints(); @@ -261,6 +264,16 @@ Java_AssistantInfoPopup_show(env, jinfo_popup, jcontext); } +std::string SafeConvertJavaStringToNative( + JNIEnv* env, + const base::android::JavaParamRef<jstring>& jstring) { + std::string native_string; + if (jstring) { + base::android::ConvertJavaStringToUTF8(env, jstring, &native_string); + } + return native_string; +} + } // namespace ui_controller_android_utils } // namespace autofill_assistant
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android_utils.h b/chrome/browser/android/autofill_assistant/ui_controller_android_utils.h index 4121d171..5f74bff 100644 --- a/chrome/browser/android/autofill_assistant/ui_controller_android_utils.h +++ b/chrome/browser/android/autofill_assistant/ui_controller_android_utils.h
@@ -51,7 +51,8 @@ base::android::ScopedJavaLocalRef<jobject> ToJavaValue(JNIEnv* env, const ValueProto& proto); -// Returns the native equivalent of |jvalue|. +// Returns the native equivalent of |jvalue|. Returns an empty ValueProto if +// |jvalue| is null. ValueProto ToNativeValue(JNIEnv* env, const base::android::JavaParamRef<jobject>& jvalue); @@ -65,6 +66,11 @@ base::android::ScopedJavaLocalRef<jobject> jinfo_popup, base::android::ScopedJavaLocalRef<jobject> jcontext); +// Converts a java string to native. Returns an empty string if input is null. +std::string SafeConvertJavaStringToNative( + JNIEnv* env, + const base::android::JavaParamRef<jstring>& jstring); + } // namespace ui_controller_android_utils } // namespace autofill_assistant
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc index f2b26b1..f3727ded 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -944,6 +944,7 @@ TestCase("searchDownloadsWithNoResults"), TestCase("searchDownloadsClearSearchKeyDown"), TestCase("searchDownloadsClearSearch"), + TestCase("searchHidingViaTab"), TestCase("searchHidingTextEntryField"))); WRAPPED_INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc index 346b0ce..f80f586 100644 --- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc +++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -207,7 +207,8 @@ device_remote_commands_invalidator_ = std::make_unique<AffiliatedRemoteCommandsInvalidator>( device_cloud_policy_manager_->core(), - affiliated_invalidation_service_provider_.get()); + affiliated_invalidation_service_provider_.get(), + PolicyInvalidationScope::kDevice); } SetTimezoneIfPolicyAvailable();
diff --git a/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc index 63bb35a..aa6fd70 100644 --- a/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc +++ b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.cc
@@ -4,15 +4,18 @@ #include "chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h" +#include "base/time/default_clock.h" #include "chrome/browser/policy/cloud/remote_commands_invalidator_impl.h" namespace policy { AffiliatedRemoteCommandsInvalidator::AffiliatedRemoteCommandsInvalidator( CloudPolicyCore* core, - AffiliatedInvalidationServiceProvider* invalidation_service_provider) + AffiliatedInvalidationServiceProvider* invalidation_service_provider, + PolicyInvalidationScope scope) : core_(core), - invalidation_service_provider_(invalidation_service_provider) { + invalidation_service_provider_(invalidation_service_provider), + scope_(scope) { invalidation_service_provider_->RegisterConsumer(this); } @@ -29,7 +32,8 @@ } // Create a new one if required. if (invalidation_service) { - invalidator_.reset(new RemoteCommandsInvalidatorImpl(core_)); + invalidator_.reset(new RemoteCommandsInvalidatorImpl( + core_, base::DefaultClock::GetInstance(), scope_)); invalidator_->Initialize(invalidation_service); } }
diff --git a/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h index 53decf6..ba2a718b 100644 --- a/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h +++ b/chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h" +#include "components/policy/core/common/cloud/policy_invalidation_scope.h" namespace policy { @@ -22,7 +23,8 @@ public: AffiliatedRemoteCommandsInvalidator( CloudPolicyCore* core, - AffiliatedInvalidationServiceProvider* invalidation_service_provider); + AffiliatedInvalidationServiceProvider* invalidation_service_provider, + PolicyInvalidationScope scope); ~AffiliatedRemoteCommandsInvalidator() override; // AffiliatedInvalidationServiceProvider::Consumer: @@ -35,6 +37,8 @@ std::unique_ptr<RemoteCommandsInvalidatorImpl> invalidator_; + const PolicyInvalidationScope scope_; + DISALLOW_COPY_AND_ASSIGN(AffiliatedRemoteCommandsInvalidator); };
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc index 30ce5f9..db49b69 100644 --- a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc +++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
@@ -2816,7 +2816,8 @@ // Create a test uploads.log file in the legacy CSV format. All such kind of // record will be ignored because the required source filed is not existing. base::Time timestamp = base::Time::Now() - base::TimeDelta::FromHours(1); - std::string test_entry = base::StringPrintf("%" PRId64, timestamp.ToTimeT()); + std::string test_entry = + base::StringPrintf("%" PRId64, static_cast<int64_t>(timestamp.ToTimeT())); test_entry += ","; test_entry.append(kTestUploadId); test_entry += ",";
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc index 6cb3ea5..1715b592 100644 --- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc +++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
@@ -17,6 +17,7 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/sequenced_task_runner.h" +#include "base/time/default_clock.h" #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/helper.h" @@ -794,7 +795,9 @@ core()->StartRemoteCommandsService( std::make_unique<UserCommandsFactoryChromeOS>(profile_)); - invalidator_ = std::make_unique<RemoteCommandsInvalidatorImpl>(core()); + invalidator_ = std::make_unique<RemoteCommandsInvalidatorImpl>( + core(), base::DefaultClock::GetInstance(), + PolicyInvalidationScope::kUser); invalidator_->Initialize( invalidation_provider->GetInvalidationServiceForCustomSender(
diff --git a/chrome/browser/downgrade/snapshot_manager.cc b/chrome/browser/downgrade/snapshot_manager.cc index 43532f06c..fa211cf 100644 --- a/chrome/browser/downgrade/snapshot_manager.cc +++ b/chrome/browser/downgrade/snapshot_manager.cc
@@ -23,6 +23,13 @@ namespace { +constexpr base::FilePath::StringPieceType kSQLiteJournalSuffix( + FILE_PATH_LITERAL("-journal")); +constexpr base::FilePath::StringPieceType kSQLiteWalSuffix( + FILE_PATH_LITERAL("-wal")); +constexpr base::FilePath::StringPieceType kSQLiteShmSuffix( + FILE_PATH_LITERAL("-shm")); + // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. enum class SnapshotOperationResult { @@ -34,25 +41,45 @@ }; // Copies the item at |user_data_dir|/|relative_path| to -// |snapshot_dir|/|relative_path| if the item exists. -// Returns |true| if the item was found at the source and successfully copied. -// Returns |false| if the item was found at the source but not successfully -// copied. Returns no value if the file was not at the source. +// |snapshot_dir|/|relative_path| if the item exists. This also copies all files +// related to items that are SQLite databases. Returns |true| if the item was +// found at the source and successfully copied. Returns |false| if the item was +// found at the source but not successfully copied. Returns no value if the file +// was not at the source. base::Optional<bool> CopyItemToSnapshotDirectory( const base::FilePath& relative_path, const base::FilePath& user_data_dir, const base::FilePath& snapshot_dir, bool is_directory) { - auto source = user_data_dir.Append(relative_path); - auto destination = snapshot_dir.Append(relative_path); + const auto source = user_data_dir.Append(relative_path); + const auto destination = snapshot_dir.Append(relative_path); // If nothing exists to be moved, do not consider it a success or a failure. if (!base::PathExists(source)) return base::nullopt; - return is_directory - ? base::CopyDirectory(source, destination, /*recursive=*/true) - : base::CopyFile(source, destination); + bool copy_success = is_directory ? base::CopyDirectory(source, destination, + /*recursive=*/true) + : base::CopyFile(source, destination); + + if (is_directory) + return copy_success; + + // Copy SQLite journal, WAL and SHM files associated with the files that are + // snapshotted if they exist. + for (const auto& suffix : + {kSQLiteJournalSuffix, kSQLiteWalSuffix, kSQLiteShmSuffix}) { + const auto sqlite_file_path = + base::FilePath(source.value() + base::FilePath::StringType(suffix)); + if (!base::PathExists(sqlite_file_path)) + continue; + + const auto destination_journal = base::FilePath( + destination.value() + base::FilePath::StringType(suffix)); + copy_success &= base::CopyFile(sqlite_file_path, destination_journal); + } + + return copy_success; } // Returns true if |base_name| matches a user profile directory's format. This
diff --git a/chrome/browser/downgrade/snapshot_manager_unittest.cc b/chrome/browser/downgrade/snapshot_manager_unittest.cc index 61f77f3..2f017dcb 100644 --- a/chrome/browser/downgrade/snapshot_manager_unittest.cc +++ b/chrome/browser/downgrade/snapshot_manager_unittest.cc
@@ -37,6 +37,14 @@ FILE_PATH_LITERAL("User Data File"); constexpr base::FilePath::StringPieceType kProfileDataFile = FILE_PATH_LITERAL("Profile Data File"); +constexpr base::FilePath::StringPieceType kProfileDataJournalFile = + FILE_PATH_LITERAL("Profile Data File-journal"); +constexpr base::FilePath::StringPieceType kProfileDataExtFile = + FILE_PATH_LITERAL("Profile Data File.ext"); +constexpr base::FilePath::StringPieceType kProfileDataExtWalFile = + FILE_PATH_LITERAL("Profile Data File.ext-wal"); +constexpr base::FilePath::StringPieceType kProfileDataExtShmFile = + FILE_PATH_LITERAL("Profile Data File.ext-shm"); constexpr std::array<base::FilePath::StringPieceType, 3> kProfileDirectoryBaseNames = {FILE_PATH_LITERAL("Default"), @@ -120,6 +128,8 @@ return std::vector<SnapshotItemDetails>{ SnapshotItemDetails(base::FilePath(kProfileDataFile), SnapshotItemDetails::ItemType::kFile, 0), + SnapshotItemDetails(base::FilePath(kProfileDataExtFile), + SnapshotItemDetails::ItemType::kFile, 0), SnapshotItemDetails(base::FilePath(kProfileDataFolder), SnapshotItemDetails::ItemType::kDirectory, 0)}; } @@ -175,6 +185,15 @@ // Files and folders at Profile Data level that should be snapshotted. base::File file(path.Append(kProfileDataFile), base::File::FLAG_CREATE | base::File::FLAG_WRITE); + base::File file_ext(path.Append(kProfileDataExtFile), + base::File::FLAG_CREATE | base::File::FLAG_WRITE); + base::File file_journal(path.Append(kProfileDataJournalFile), + base::File::FLAG_CREATE | base::File::FLAG_WRITE); + base::File file_ext_wal(path.Append(kProfileDataExtWalFile), + base::File::FLAG_CREATE | base::File::FLAG_WRITE); + base::File file_ext_shm(path.Append(kProfileDataExtShmFile), + base::File::FLAG_CREATE | base::File::FLAG_WRITE); + ASSERT_NO_FATAL_FAILURE(TestFolderAndFiles::CreateFilesAndFolders( path.Append(kProfileDataFolder))); @@ -196,6 +215,10 @@ for (const auto& path : absolute_profile_paths) { EXPECT_TRUE(base::PathExists(path.Append(kProfileDataFile))); + EXPECT_TRUE(base::PathExists(path.Append(kProfileDataExtFile))); + EXPECT_TRUE(base::PathExists(path.Append(kProfileDataJournalFile))); + EXPECT_TRUE(base::PathExists(path.Append(kProfileDataExtWalFile))); + EXPECT_TRUE(base::PathExists(path.Append(kProfileDataExtShmFile))); EXPECT_TRUE(base::DirectoryExists(path.Append(kProfileDataFolder))); EXPECT_TRUE(TestFolderAndFiles::AllPathExists(path)); } @@ -203,6 +226,14 @@ for (const auto& path : kProfileDirectoryBaseNames) { EXPECT_TRUE( base::PathExists(snapshot_dir.Append(path).Append(kProfileDataFile))); + EXPECT_TRUE(base::PathExists( + snapshot_dir.Append(path).Append(kProfileDataJournalFile))); + EXPECT_TRUE(base::PathExists( + snapshot_dir.Append(path).Append(kProfileDataExtFile))); + EXPECT_TRUE(base::PathExists( + snapshot_dir.Append(path).Append(kProfileDataExtWalFile))); + EXPECT_TRUE(base::PathExists( + snapshot_dir.Append(path).Append(kProfileDataExtShmFile))); EXPECT_TRUE(base::DirectoryExists( snapshot_dir.Append(path).Append(kProfileDataFolder))); EXPECT_TRUE(TestFolderAndFiles::NoPathExists(snapshot_dir.Append(path)));
diff --git a/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc b/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc index e7be3c24..dc0cb5e 100644 --- a/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc +++ b/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc
@@ -142,7 +142,8 @@ &saved_passwords_presenter_), bulk_leak_check_service_adapter_( &saved_passwords_presenter_, - BulkLeakCheckServiceFactory::GetForProfile(profile_)) { + BulkLeakCheckServiceFactory::GetForProfile(profile_), + profile_->GetPrefs()) { observed_saved_passwords_presenter_.Add(&saved_passwords_presenter_); observed_compromised_credentials_provider_.Add( &compromised_credentials_provider_);
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.cc index ea89dc6e..d8d4d0b 100644 --- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.cc +++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.cc
@@ -6,6 +6,8 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h" +#include "chrome/browser/password_manager/bulk_leak_check_service_factory.h" +#include "chrome/browser/password_manager/password_store_factory.h" #include "chrome/browser/profiles/profile.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "extensions/browser/extension_system_provider.h" @@ -25,17 +27,19 @@ // static PasswordsPrivateDelegateFactory* PasswordsPrivateDelegateFactory::GetInstance() { - return base::Singleton<PasswordsPrivateDelegateFactory>::get(); + static base::NoDestructor<PasswordsPrivateDelegateFactory> instance; + return instance.get(); } PasswordsPrivateDelegateFactory::PasswordsPrivateDelegateFactory() : BrowserContextKeyedServiceFactory( "PasswordsPrivateDelegate", BrowserContextDependencyManager::GetInstance()) { + DependsOn(BulkLeakCheckServiceFactory::GetInstance()); + DependsOn(PasswordStoreFactory::GetInstance()); } -PasswordsPrivateDelegateFactory::~PasswordsPrivateDelegateFactory() { -} +PasswordsPrivateDelegateFactory::~PasswordsPrivateDelegateFactory() = default; KeyedService* PasswordsPrivateDelegateFactory::BuildServiceInstanceFor( content::BrowserContext* profile) const {
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h index e28c3bf..7afbd345 100644 --- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h +++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h
@@ -5,8 +5,7 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_PASSWORDS_PRIVATE_PASSWORDS_PRIVATE_DELEGATE_FACTORY_H_ #define CHROME_BROWSER_EXTENSIONS_API_PASSWORDS_PRIVATE_PASSWORDS_PRIVATE_DELEGATE_FACTORY_H_ -#include "base/macros.h" -#include "base/memory/singleton.h" +#include "base/no_destructor.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" namespace context { @@ -27,8 +26,7 @@ static PasswordsPrivateDelegateFactory* GetInstance(); private: - friend struct base::DefaultSingletonTraits<PasswordsPrivateDelegateFactory>; - + friend class base::NoDestructor<PasswordsPrivateDelegateFactory>; PasswordsPrivateDelegateFactory(); ~PasswordsPrivateDelegateFactory() override; @@ -37,8 +35,6 @@ content::BrowserContext* profile) const override; bool ServiceIsCreatedWithBrowserContext() const override; bool ServiceIsNULLWhileTesting() const override; - - DISALLOW_COPY_AND_ASSIGN(PasswordsPrivateDelegateFactory); }; } // namespace extensions
diff --git a/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc b/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc index 2c09a117a..5b46af7 100644 --- a/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc +++ b/chrome/browser/favicon/history_ui_favicon_request_handler_factory.cc
@@ -11,27 +11,14 @@ #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/profile_sync_service_factory.h" -#include "chrome/browser/sync/session_sync_service_factory.h" #include "components/favicon/core/history_ui_favicon_request_handler_impl.h" -#include "components/favicon_base/favicon_types.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_service_utils.h" -#include "components/sync_sessions/open_tabs_ui_delegate.h" -#include "components/sync_sessions/session_sync_service.h" #include "content/public/browser/browser_context.h" namespace { -favicon_base::FaviconRawBitmapResult GetSyncedFaviconForPageUrl( - sync_sessions::SessionSyncService* session_sync_service, - const GURL& page_url) { - sync_sessions::OpenTabsUIDelegate* open_tabs = - session_sync_service->GetOpenTabsUIDelegate(); - return open_tabs ? open_tabs->GetSyncedFaviconForPageURL(page_url) - : favicon_base::FaviconRawBitmapResult(); -} - bool CanSendHistoryData(syncer::SyncService* sync_service) { return syncer::GetUploadToGoogleState(sync_service, syncer::ModelType::SESSIONS) == @@ -60,7 +47,6 @@ BrowserContextDependencyManager::GetInstance()) { DependsOn(FaviconServiceFactory::GetInstance()); DependsOn(LargeIconServiceFactory::GetInstance()); - DependsOn(SessionSyncServiceFactory::GetInstance()); DependsOn(ProfileSyncServiceFactory::GetInstance()); } @@ -77,8 +63,6 @@ content::BrowserContext* context) const { Profile* profile = Profile::FromBrowserContext(context); return new favicon::HistoryUiFaviconRequestHandlerImpl( - base::BindRepeating(&GetSyncedFaviconForPageUrl, - SessionSyncServiceFactory::GetForProfile(profile)), base::BindRepeating(&CanSendHistoryData, ProfileSyncServiceFactory::GetForProfile(profile)), FaviconServiceFactory::GetForProfile(profile,
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 2d10673..d510c1c 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -284,6 +284,11 @@ "expiry_milestone": 73 }, { + "name": "autofill-ios-delay-between-fields", + "owners": [ "olivierrobin" ], + "expiry_milestone": 86 + }, + { "name": "autofill-keyboard-accessory-view", "owners": [ "fhorschig@chromium.org" ], "expiry_milestone": 83 @@ -344,6 +349,11 @@ "expiry_milestone": 84 }, { + "name": "autofill-show-all-profiles-on-prefilled-forms", + "owners": [ "olivierrobin" ], + "expiry_milestone": 86 + }, + { "name": "autofill-use-improved-label-disambiguation", "owners": [ "fhorschig" ], "expiry_milestone": 83 @@ -3109,6 +3119,11 @@ "expiry_milestone": 76 }, { + "name": "open-downloads-in-files.app", + "owners": [ "ewannpv", "gambard" ], + "expiry_milestone": 86 + }, + { "name": "overlay-new-layout", "owners": [ "donnd", "jinsukkim", "contextual-search-eng" ], "expiry_milestone": 81
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index f3e6c311..67ec332 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -157,7 +157,6 @@ &kHorizontalTabSwitcherAndroid, &kImmersiveUiMode, &kInlineUpdateFlow, - &kIntentBlockExternalFormRedirectsNoGesture, &kKitKatSupported, &kNewPhotoPicker, &kNotificationSuspender, @@ -458,10 +457,6 @@ const base::Feature kInlineUpdateFlow{"InlineUpdateFlow", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kIntentBlockExternalFormRedirectsNoGesture{ - "IntentBlockExternalFormRedirectsNoGesture", - base::FEATURE_DISABLED_BY_DEFAULT}; - const base::Feature kKitKatSupported{"KitKatSupported", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index 70aa2fc..21815f7 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -78,7 +78,6 @@ extern const base::Feature kImmersiveUiMode; extern const base::Feature kImprovedA2HS; extern const base::Feature kInlineUpdateFlow; -extern const base::Feature kIntentBlockExternalFormRedirectsNoGesture; extern const base::Feature kKitKatSupported; extern const base::Feature kLanguagesPreference; extern const base::Feature kNewPhotoPicker;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 597c893..b14928cb5 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -310,8 +310,6 @@ "ImprovedCookieControlsForThirdPartyCookieBlocking"; public static final String INLINE_UPDATE_FLOW = "InlineUpdateFlow"; public static final String INSTALLABLE_AMBIENT_BADGE_INFOBAR = "InstallableAmbientBadgeInfoBar"; - public static final String INTENT_BLOCK_EXTERNAL_FORM_REDIRECT_NO_GESTURE = - "IntentBlockExternalFormRedirectsNoGesture"; public static final String INTEREST_FEED_CONTENT_SUGGESTIONS = "InterestFeedContentSuggestions"; public static final String INTEREST_FEED_FEEDBACK = "InterestFeedFeedback"; public static final String KITKAT_SUPPORTED = "KitKatSupported";
diff --git a/chrome/browser/media/feeds/media_feeds_browsertest.cc b/chrome/browser/media/feeds/media_feeds_browsertest.cc index eabe0572..076d0fe 100644 --- a/chrome/browser/media/feeds/media_feeds_browsertest.cc +++ b/chrome/browser/media/feeds/media_feeds_browsertest.cc
@@ -8,6 +8,7 @@ #include "base/task/post_task.h" #include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" +#include "build/build_config.h" #include "chrome/browser/media/feeds/media_feeds_contents_observer.h" #include "chrome/browser/media/history/media_history_feeds_table.h" #include "chrome/browser/media/history/media_history_keyed_service.h" @@ -123,7 +124,14 @@ "<link rel=other type=\"application/ld+json\" href=\"/test\"/>", false})); -IN_PROC_BROWSER_TEST_P(MediaFeedsBrowserTest, Discover) { +// Crashes on Mac/Win only. http://crbug.com/1060626 +#if defined(OS_WIN) || defined(OS_MACOSX) +#define MAYBE_Discover DISABLED_Discover +#else +#define MAYBE_Discover Discover +#endif + +IN_PROC_BROWSER_TEST_P(MediaFeedsBrowserTest, MAYBE_Discover) { EXPECT_TRUE(GetDiscoveredFeedURLs().empty()); MediaFeedsContentsObserver* contents_observer =
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc index 70ced8d6..9ae80a2 100644 --- a/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc +++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc
@@ -197,7 +197,7 @@ OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile()) ->RegisterOptimizationTypesAndTargets( {optimization_guide::proto::NOSCRIPT}, - /*optimization_targets=*/{}); + {optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD}); // Set up an OptimizationGuideKeyedService consumer. consumer_.reset(new OptimizationGuideConsumerWebContentsObserver(
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc b/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc index 338ad01..d2bc264 100644 --- a/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc +++ b/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
@@ -255,6 +255,7 @@ } void SetUpCommandLine(base::CommandLine* cmd) override { + cmd->AppendSwitch("enable-spdy-proxy-auth"); cmd->AppendSwitch(optimization_guide::switches:: kFetchModelsAndHostModelFeaturesOverrideTimer);
diff --git a/chrome/browser/password_manager/password_manager_test_base.cc b/chrome/browser/password_manager/password_manager_test_base.cc index ba72faa..08aaaea 100644 --- a/chrome/browser/password_manager/password_manager_test_base.cc +++ b/chrome/browser/password_manager/password_manager_test_base.cc
@@ -19,16 +19,17 @@ #include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/password_manager/password_store_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/ui/autofill/chrome_autofill_client.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/ui_test_utils.h" #include "components/autofill/core/browser/autofill_test_utils.h" -#include "components/password_manager/core/browser/mock_password_feature_manager.h" -#include "components/password_manager/core/browser/password_feature_manager.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/password_manager/core/browser/password_manager_test_utils.h" #include "components/password_manager/core/browser/test_password_store.h" +#include "components/sync/driver/test_sync_service.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_handle.h" @@ -45,56 +46,10 @@ namespace { -// A helper class that synchronously waits until the password store handles a -// GetLogins() request. -class PasswordStoreResultsObserver - : public password_manager::PasswordStoreConsumer { - public: - PasswordStoreResultsObserver() = default; - - void OnGetPasswordStoreResults( - std::vector<std::unique_ptr<autofill::PasswordForm>> results) override { - run_loop_.Quit(); - } - - void Wait() { run_loop_.Run(); } - - private: - base::RunLoop run_loop_; - - DISALLOW_COPY_AND_ASSIGN(PasswordStoreResultsObserver); -}; - -// Custom class is required to enable password generation. -class CustomPasswordManagerClient : public ChromePasswordManagerClient { - public: - using ChromePasswordManagerClient::ChromePasswordManagerClient; - CustomPasswordManagerClient(content::WebContents* contents, - autofill::AutofillClient* autofill_client) - : ChromePasswordManagerClient(contents, autofill_client) { - ON_CALL(password_feature_manager_, IsGenerationEnabled()) - .WillByDefault(testing::Return(true)); - } - - static void CreateForWebContentsWithAutofillClient( - content::WebContents* contents, - autofill::AutofillClient* autofill_client) { - ASSERT_FALSE(FromWebContents(contents)); - contents->SetUserData(UserDataKey(), - std::make_unique<CustomPasswordManagerClient>( - contents, autofill_client)); - } - - // PasswordManagerClient: - password_manager::PasswordFeatureManager* GetPasswordFeatureManager() - override { - return &password_feature_manager_; - } - - private: - testing::NiceMock<password_manager::MockPasswordFeatureManager> - password_feature_manager_; -}; +std::unique_ptr<KeyedService> BuildTestSyncService( + content::BrowserContext* context) { + return std::make_unique<syncer::TestSyncService>(); +} // ManagePasswordsUIController subclass to capture the UI events. class CustomManagePasswordsUIController : public ManagePasswordsUIController { @@ -435,6 +390,21 @@ return controller->WaitForFallbackForSaving(timeout); } +PasswordStoreResultsObserver::PasswordStoreResultsObserver() = default; +PasswordStoreResultsObserver::~PasswordStoreResultsObserver() = default; + +void PasswordStoreResultsObserver::OnGetPasswordStoreResults( + std::vector<std::unique_ptr<autofill::PasswordForm>> results) { + results_ = std::move(results); + run_loop_.Quit(); +} + +std::vector<std::unique_ptr<autofill::PasswordForm>> +PasswordStoreResultsObserver::WaitForResults() { + run_loop_.Run(); + return std::move(results_); +} + PasswordManagerBrowserTestBase::PasswordManagerBrowserTestBase() : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS), web_contents_(nullptr) {} @@ -468,6 +438,7 @@ ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); } +// static void PasswordManagerBrowserTestBase::SetUpOnMainThreadAndGetNewTab( Browser* browser, content::WebContents** web_contents) { @@ -482,19 +453,26 @@ &password_manager::BuildPasswordStore< content::BrowserContext, password_manager::TestPasswordStore>)); + GetNewTab(browser, web_contents); +} + +// static +void PasswordManagerBrowserTestBase::GetNewTab( + Browser* browser, + content::WebContents** web_contents) { // Add a tab with a customized ManagePasswordsUIController. Thus, we can // intercept useful UI events. - content::WebContents* tab = + content::WebContents* preexisting_tab = browser->tab_strip_model()->GetActiveWebContents(); std::unique_ptr<content::WebContents> owned_web_contents = content::WebContents::Create( - content::WebContents::CreateParams(tab->GetBrowserContext())); + content::WebContents::CreateParams(browser->profile())); *web_contents = owned_web_contents.get(); ASSERT_TRUE(*web_contents); // ManagePasswordsUIController needs ChromePasswordManagerClient for logging. autofill::ChromeAutofillClient::CreateForWebContents(*web_contents); - CustomPasswordManagerClient::CreateForWebContentsWithAutofillClient( + ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient( *web_contents, autofill::ChromeAutofillClient::FromWebContents(*web_contents)); ASSERT_TRUE(ChromePasswordManagerClient::FromWebContents(*web_contents)); @@ -502,20 +480,24 @@ new CustomManagePasswordsUIController(*web_contents); browser->tab_strip_model()->AppendWebContents(std::move(owned_web_contents), true); - browser->tab_strip_model()->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE); + if (preexisting_tab) { + browser->tab_strip_model()->CloseWebContentsAt(0, + TabStripModel::CLOSE_NONE); + } ASSERT_EQ(controller, ManagePasswordsUIController::FromWebContents(*web_contents)); ASSERT_EQ(*web_contents, browser->tab_strip_model()->GetActiveWebContents()); ASSERT_FALSE((*web_contents)->IsLoading()); } +// static void PasswordManagerBrowserTestBase::WaitForPasswordStore(Browser* browser) { scoped_refptr<password_manager::PasswordStore> password_store = PasswordStoreFactory::GetForProfile(browser->profile(), ServiceAccessType::IMPLICIT_ACCESS); PasswordStoreResultsObserver syncer; password_store->GetAllLoginsWithAffiliationAndBrandingInformation(&syncer); - syncer.Wait(); + syncer.WaitForResults(); } content::WebContents* PasswordManagerBrowserTestBase::WebContents() const { @@ -681,6 +663,23 @@ EXPECT_EQ(expected_value, return_value) << "element_id = " << element_id; } +void PasswordManagerBrowserTestBase::SetUpInProcessBrowserTestFixture() { + will_create_browser_context_services_subscription_ = + BrowserContextDependencyManager::GetInstance() + ->RegisterWillCreateBrowserContextServicesCallbackForTesting( + base::BindRepeating(&PasswordManagerBrowserTestBase:: + OnWillCreateBrowserContextServices)); +} + +// static +void PasswordManagerBrowserTestBase::OnWillCreateBrowserContextServices( + content::BrowserContext* context) { + // Set up a TestSyncService which will happily return "everything is active" + // so that password generation is considered enabled. + ProfileSyncServiceFactory::GetInstance()->SetTestingFactory( + context, base::BindRepeating(&BuildTestSyncService)); +} + void PasswordManagerBrowserTestBase::AddHSTSHost(const std::string& host) { network::mojom::NetworkContext* network_context = content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
diff --git a/chrome/browser/password_manager/password_manager_test_base.h b/chrome/browser/password_manager/password_manager_test_base.h index 7bf799c..d5735a7 100644 --- a/chrome/browser/password_manager/password_manager_test_base.h +++ b/chrome/browser/password_manager/password_manager_test_base.h
@@ -7,6 +7,7 @@ #include <memory> +#include "base/callback_list.h" #include "base/macros.h" #include "base/run_loop.h" #include "chrome/browser/ssl/cert_verifier_browser_test.h" @@ -134,12 +135,34 @@ DISALLOW_COPY_AND_ASSIGN(BubbleObserver); }; +// A helper class that synchronously waits until the password store handles a +// GetLogins() request. +class PasswordStoreResultsObserver + : public password_manager::PasswordStoreConsumer { + public: + PasswordStoreResultsObserver(); + ~PasswordStoreResultsObserver() override; + + // Waits for OnGetPasswordStoreResults() and returns the result. + std::vector<std::unique_ptr<autofill::PasswordForm>> WaitForResults(); + + private: + void OnGetPasswordStoreResults( + std::vector<std::unique_ptr<autofill::PasswordForm>> results) override; + + base::RunLoop run_loop_; + std::vector<std::unique_ptr<autofill::PasswordForm>> results_; + + DISALLOW_COPY_AND_ASSIGN(PasswordStoreResultsObserver); +}; + class PasswordManagerBrowserTestBase : public CertVerifierBrowserTest { public: PasswordManagerBrowserTestBase(); ~PasswordManagerBrowserTestBase() override; // InProcessBrowserTest: + void SetUpInProcessBrowserTestFixture() override; void SetUpOnMainThread() override; void TearDownOnMainThread() override; @@ -151,6 +174,11 @@ static void SetUpOnMainThreadAndGetNewTab( Browser* browser, content::WebContents** web_contents); + + // Creates a new tab with all the password manager test hooks and returns it + // in |web_contents|. + static void GetNewTab(Browser* browser, content::WebContents** web_contents); + // Make sure that the password store associated with the given browser // processed all the previous calls, calls executed on another thread. static void WaitForPasswordStore(Browser* browser); @@ -217,9 +245,17 @@ net::EmbeddedTestServer& https_test_server() { return https_test_server_; } private: + static void OnWillCreateBrowserContextServices( + content::BrowserContext* context); + net::EmbeddedTestServer https_test_server_; // A tab with some hooks injected. content::WebContents* web_contents_; + + std::unique_ptr< + base::CallbackList<void(content::BrowserContext*)>::Subscription> + will_create_browser_context_services_subscription_; + DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTestBase); };
diff --git a/chrome/browser/payments/android/service_worker_payment_app_bridge.cc b/chrome/browser/payments/android/service_worker_payment_app_bridge.cc index 3f5cc9b1..e7b5e7b 100644 --- a/chrome/browser/payments/android/service_worker_payment_app_bridge.cc +++ b/chrome/browser/payments/android/service_worker_payment_app_bridge.cc
@@ -423,7 +423,10 @@ content::WebContents::FromJavaWebContents(jweb_contents); payments::ServiceWorkerPaymentAppFinder::GetInstance()->GetAllPaymentApps( - url::Origin::FromJavaObject(jorigin), web_contents, + url::Origin::FromJavaObject(jorigin), + // TODO(crbug.com/1055360): plumb the RenderFrameHost from Java side. + nullptr, /* initiator_render_frame_host */ + web_contents, WebDataServiceFactory::GetPaymentManifestWebDataForProfile( Profile::FromBrowserContext(web_contents->GetBrowserContext()), ServiceAccessType::EXPLICIT_ACCESS),
diff --git a/chrome/browser/payments/service_worker_payment_app_finder_browsertest.cc b/chrome/browser/payments/service_worker_payment_app_finder_browsertest.cc index 548f1a8d876..452436be 100644 --- a/chrome/browser/payments/service_worker_payment_app_finder_browsertest.cc +++ b/chrome/browser/payments/service_worker_payment_app_finder_browsertest.cc
@@ -185,7 +185,8 @@ base::RunLoop run_loop; ServiceWorkerPaymentAppFinder::GetInstance()->GetAllPaymentApps( - url::Origin::Create(GURL("https://chromium.org")), web_contents, + url::Origin::Create(GURL("https://chromium.org")), + web_contents->GetMainFrame(), web_contents, WebDataServiceFactory::GetPaymentManifestWebDataForProfile( Profile::FromBrowserContext(context), ServiceAccessType::EXPLICIT_ACCESS),
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc index 83683d7..0991541 100644 --- a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc +++ b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
@@ -89,8 +89,6 @@ const int CloudPolicyInvalidator::kMaxFetchDelayMin = 1000; const int CloudPolicyInvalidator::kMaxFetchDelayMax = 300000; const int CloudPolicyInvalidator::kInvalidationGracePeriod = 10; -const int CloudPolicyInvalidator::kUnknownVersionIgnorePeriod = 30; -const int CloudPolicyInvalidator::kMaxInvalidationTimeDelta = 300; // static const char* CloudPolicyInvalidator::GetPolicyRefreshMetricName( @@ -334,7 +332,11 @@ } // Ignore the invalidation if it is expired. - const bool is_expired = IsInvalidationExpired(version); + const auto last_fetch_time = + base::Time::FromJavaTime(core_->store()->policy()->timestamp()); + const auto current_time = clock_->Now(); + const bool is_expired = + IsInvalidationExpired(invalidation, last_fetch_time, current_time); const bool is_missing_payload = payload.empty(); RecordPolicyInvalidationMetric(scope_, is_expired, is_missing_payload); @@ -494,27 +496,6 @@ return changed; } -bool CloudPolicyInvalidator::IsInvalidationExpired(int64_t version) { - base::Time last_fetch_time = - base::Time::FromJavaTime(core_->store()->policy()->timestamp()); - - // If the version is unknown, consider the invalidation invalid if the - // policy was fetched very recently. - if (version < 0) { - base::TimeDelta elapsed = clock_->Now() - last_fetch_time; - return elapsed.InSeconds() < kUnknownVersionIgnorePeriod; - } - - // The invalidation version is the timestamp in microseconds. If the - // invalidation occurred before the last policy fetch, then the invalidation - // is expired. Time is added to the invalidation to err on the side of not - // expired. - base::Time invalidation_time = base::Time::UnixEpoch() + - base::TimeDelta::FromMicroseconds(version) + - base::TimeDelta::FromSeconds(kMaxInvalidationTimeDelta); - return invalidation_time < last_fetch_time; -} - bool CloudPolicyInvalidator::GetInvalidationsEnabled() { if (!invalidations_enabled_) return false;
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator.h b/chrome/browser/policy/cloud/cloud_policy_invalidator.h index bc3c6ba5..a441905 100644 --- a/chrome/browser/policy/cloud/cloud_policy_invalidator.h +++ b/chrome/browser/policy/cloud/cloud_policy_invalidator.h
@@ -53,14 +53,6 @@ // once the invalidation service starts up. static const int kInvalidationGracePeriod; - // Time, in seconds, for which unknown version invalidations are ignored after - // fetching a policy. - static const int kUnknownVersionIgnorePeriod; - - // The max tolerated discrepancy, in seconds, between policy timestamps and - // invalidation timestamps when determining if an invalidation is expired. - static const int kMaxInvalidationTimeDelta; - // Returns a name of a refresh metric associated with the given scope. static const char* GetPolicyRefreshMetricName(PolicyInvalidationScope scope); // Returns a name of a FCM refresh metric associated with the given scope. @@ -170,10 +162,6 @@ // previous call. bool IsPolicyChanged(const enterprise_management::PolicyData* policy); - // Determine if an invalidation has expired. - // |version| is the version of the invalidation, or zero for unknown. - bool IsInvalidationExpired(int64_t version); - // Determine if invalidations have been enabled longer than the grace period. bool GetInvalidationsEnabled();
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc index f9ca311..b784b33 100644 --- a/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc +++ b/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc
@@ -24,6 +24,7 @@ #include "base/time/time.h" #include "base/values.h" #include "build/build_config.h" +#include "chrome/browser/policy/cloud/policy_invalidation_util.h" #include "chrome/browser/policy/cloud/user_cloud_policy_invalidator.h" #include "components/invalidation/impl/fake_invalidation_service.h" #include "components/invalidation/impl/invalidator_registrar_with_memory.h" @@ -1055,8 +1056,8 @@ // Invalidations fired before the last fetch time (adjusted by max time delta) // should be ignored. - base::Time time = Now() - base::TimeDelta::FromSeconds( - CloudPolicyInvalidator::kMaxInvalidationTimeDelta + 300); + base::Time time = Now() - (invalidation_timeouts::kMaxInvalidationTimeDelta + + base::TimeDelta::FromSeconds(300)); syncer::Invalidation inv = FireInvalidation(POLICY_OBJECT_A, GetVersion(time), "test"); ASSERT_TRUE(IsInvalidationAcknowledged(inv)); @@ -1089,8 +1090,8 @@ ASSERT_TRUE(IsInvalidationAcknowledged(inv)); ASSERT_TRUE(CheckPolicyNotRefreshed()); - AdvanceClock(base::TimeDelta::FromSeconds( - CloudPolicyInvalidator::kUnknownVersionIgnorePeriod - 1)); + AdvanceClock(invalidation_timeouts::kUnknownVersionIgnorePeriod - + base::TimeDelta::FromSeconds(1)); inv = FireUnknownVersionInvalidation(POLICY_OBJECT_A); ASSERT_TRUE(IsInvalidationAcknowledged(inv)); ASSERT_TRUE(CheckPolicyNotRefreshed());
diff --git a/chrome/browser/policy/cloud/policy_invalidation_util.cc b/chrome/browser/policy/cloud/policy_invalidation_util.cc index 3b30c5c..408dfe4 100644 --- a/chrome/browser/policy/cloud/policy_invalidation_util.cc +++ b/chrome/browser/policy/cloud/policy_invalidation_util.cc
@@ -43,4 +43,36 @@ return true; } +bool IsInvalidationExpired(const syncer::Invalidation& invalidation, + const base::Time& last_fetch_time, + const base::Time& current_time) { + // If the version is unknown, consider the invalidation invalid if the + // fetch was very recently. + if (invalidation.is_unknown_version()) { + base::TimeDelta elapsed = current_time - last_fetch_time; + return elapsed < invalidation_timeouts::kUnknownVersionIgnorePeriod; + } + + // The invalidation version is the timestamp in microseconds. If the + // invalidation occurred before the last fetch, then the invalidation + // is expired. + base::Time invalidation_time = + base::Time::UnixEpoch() + + base::TimeDelta::FromMicroseconds(invalidation.version()) + + invalidation_timeouts::kMaxInvalidationTimeDelta; + return invalidation_time < last_fetch_time; +} + +PolicyInvalidationType GetInvalidationMetric(bool is_missing_payload, + bool is_expired) { + if (is_expired) { + if (is_missing_payload) + return POLICY_INVALIDATION_TYPE_NO_PAYLOAD_EXPIRED; + return POLICY_INVALIDATION_TYPE_EXPIRED; + } + if (is_missing_payload) + return POLICY_INVALIDATION_TYPE_NO_PAYLOAD; + return POLICY_INVALIDATION_TYPE_NORMAL; +} + } // namespace policy
diff --git a/chrome/browser/policy/cloud/policy_invalidation_util.h b/chrome/browser/policy/cloud/policy_invalidation_util.h index f36b2aa..3a69e78f 100644 --- a/chrome/browser/policy/cloud/policy_invalidation_util.h +++ b/chrome/browser/policy/cloud/policy_invalidation_util.h
@@ -5,7 +5,9 @@ #ifndef CHROME_BROWSER_POLICY_CLOUD_POLICY_INVALIDATION_UTIL_H_ #define CHROME_BROWSER_POLICY_CLOUD_POLICY_INVALIDATION_UTIL_H_ +#include "base/time/time.h" #include "components/invalidation/public/invalidation_util.h" +#include "components/policy/core/common/cloud/enterprise_metrics.h" namespace enterprise_management { @@ -13,8 +15,29 @@ } // namespace enterprise_management +namespace syncer { + +class Invalidation; + +} // namespace syncer + namespace policy { +namespace invalidation_timeouts { + +// Time for which unknown version invalidations are ignored after +// fetching a policy or command. +constexpr base::TimeDelta kUnknownVersionIgnorePeriod = + base::TimeDelta::FromSeconds(30); + +// The max tolerated discrepancy between policy or remote commands +// timestamps and invalidation timestamps when determining if an invalidation +// is expired. +constexpr base::TimeDelta kMaxInvalidationTimeDelta = + base::TimeDelta::FromSeconds(300); + +} // namespace invalidation_timeouts + // Returns true if |topic| is a public topic. Topic can be either public or // private. Private topic is keyed by GAIA ID, while public isn't, so many // users can be subscribed to the same public topic. @@ -38,6 +61,15 @@ const enterprise_management::PolicyData& policy, syncer::Topic* topic); +// Determines if an invalidation is expired. +bool IsInvalidationExpired(const syncer::Invalidation& invalidation, + const base::Time& last_fetch_time, + const base::Time& current_time); + +// Returns a metric type depended on invalidation's state. +PolicyInvalidationType GetInvalidationMetric(bool is_missing_payload, + bool is_expired); + } // namespace policy #endif // CHROME_BROWSER_POLICY_CLOUD_POLICY_INVALIDATION_UTIL_H_
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator.cc b/chrome/browser/policy/cloud/remote_commands_invalidator.cc index aeb9d29c..89f6328e 100644 --- a/chrome/browser/policy/cloud/remote_commands_invalidator.cc +++ b/chrome/browser/policy/cloud/remote_commands_invalidator.cc
@@ -7,6 +7,7 @@ #include <string> #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "chrome/browser/policy/cloud/policy_invalidation_util.h" #include "components/invalidation/public/invalidation.h" #include "components/invalidation/public/invalidation_service.h" @@ -14,6 +15,7 @@ #include "components/invalidation/public/invalidator_state.h" #include "components/invalidation/public/single_object_invalidation_set.h" #include "components/invalidation/public/topic_invalidation_map.h" +#include "components/policy/core/common/cloud/enterprise_metrics.h" namespace policy { @@ -94,7 +96,7 @@ for (const auto& it : list) it.Acknowledge(); - DoRemoteCommandsFetch(); + DoRemoteCommandsFetch(list.back()); } std::string RemoteCommandsInvalidator::GetOwnerName() const { @@ -139,8 +141,11 @@ UpdateInvalidationsEnabled(); // Update subscription with the invalidation service. - CHECK( - invalidation_service_->UpdateInterestedTopics(this, /*topics=*/{topic})); + const bool success = + invalidation_service_->UpdateInterestedTopics(this, /*topics=*/{topic}); + base::UmaHistogramBoolean(kMetricRemoteCommandInvalidationsRegistrationResult, + success); + CHECK(success); } void RemoteCommandsInvalidator::Unregister() {
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator.h b/chrome/browser/policy/cloud/remote_commands_invalidator.h index 7ea35436..21f2a39 100644 --- a/chrome/browser/policy/cloud/remote_commands_invalidator.h +++ b/chrome/browser/policy/cloud/remote_commands_invalidator.h
@@ -15,6 +15,10 @@ class InvalidationService; } // namespace invalidation +namespace syncer { +class Invalidation; +} // namespace syncer + namespace policy { // This class provides basic intefaces for an invalidator for remote commands @@ -65,7 +69,8 @@ // Subclasses must override this method to implement the actual remote // commands fetch. - virtual void DoRemoteCommandsFetch() = 0; + virtual void DoRemoteCommandsFetch( + const syncer::Invalidation& invalidation) = 0; // Subclasses must call this function to set the topic for remote command // invalidations.
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc index 51fbc5c..deccc464 100644 --- a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc +++ b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.cc
@@ -5,13 +5,37 @@ #include "chrome/browser/policy/cloud/remote_commands_invalidator_impl.h" #include "base/logging.h" +#include "base/metrics/histogram_functions.h" +#include "base/time/clock.h" +#include "chrome/browser/policy/cloud/policy_invalidation_util.h" +#include "components/invalidation/public/invalidation.h" +#include "components/policy/core/common/cloud/enterprise_metrics.h" #include "components/policy/core/common/remote_commands/remote_commands_service.h" namespace policy { +namespace { + +const char* GetInvalidationMetricName(PolicyInvalidationScope scope) { + switch (scope) { + case PolicyInvalidationScope::kUser: + return kMetricUserRemoteCommandInvalidations; + case PolicyInvalidationScope::kDevice: + return kMetricDeviceRemoteCommandInvalidations; + case PolicyInvalidationScope::kDeviceLocalAccount: + NOTREACHED() << "Unexpected instance of remote commands invalidator with " + "device local account scope."; + return ""; + } +} + +} // namespace + RemoteCommandsInvalidatorImpl::RemoteCommandsInvalidatorImpl( - CloudPolicyCore* core) - : core_(core) { + CloudPolicyCore* core, + base::Clock* clock, + PolicyInvalidationScope scope) + : core_(core), clock_(clock), scope_(scope) { DCHECK(core_); } @@ -34,8 +58,12 @@ core_->store()->RemoveObserver(this); } -void RemoteCommandsInvalidatorImpl::DoRemoteCommandsFetch() { +void RemoteCommandsInvalidatorImpl::DoRemoteCommandsFetch( + const syncer::Invalidation& invalidation) { DCHECK(core_->remote_commands_service()); + + RecordInvalidationMetric(invalidation); + core_->remote_commands_service()->FetchRemoteCommands(); } @@ -62,4 +90,20 @@ void RemoteCommandsInvalidatorImpl::OnStoreError(CloudPolicyStore* core) { } +void RemoteCommandsInvalidatorImpl::RecordInvalidationMetric( + const syncer::Invalidation& invalidation) const { + const auto last_fetch_time = + base::Time::FromJavaTime(core_->store()->policy()->timestamp()); + const auto current_time = clock_->Now(); + const bool is_expired = + IsInvalidationExpired(invalidation, last_fetch_time, current_time); + const bool is_missing_payload = + invalidation.is_unknown_version() || invalidation.payload().empty(); + + base::UmaHistogramEnumeration( + GetInvalidationMetricName(scope_), + GetInvalidationMetric(is_missing_payload, is_expired), + POLICY_INVALIDATION_TYPE_SIZE); +} + } // namespace policy
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h index aca0aef..b8b2581 100644 --- a/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h +++ b/chrome/browser/policy/cloud/remote_commands_invalidator_impl.h
@@ -9,6 +9,11 @@ #include "chrome/browser/policy/cloud/remote_commands_invalidator.h" #include "components/policy/core/common/cloud/cloud_policy_core.h" #include "components/policy/core/common/cloud/cloud_policy_store.h" +#include "components/policy/core/common/cloud/policy_invalidation_scope.h" + +namespace base { +class Clock; +} namespace policy { @@ -19,14 +24,16 @@ public CloudPolicyCore::Observer, public CloudPolicyStore::Observer { public: - explicit RemoteCommandsInvalidatorImpl(CloudPolicyCore* core); + RemoteCommandsInvalidatorImpl(CloudPolicyCore* core, + base::Clock* clock, + PolicyInvalidationScope scope); // RemoteCommandsInvalidator: void OnInitialize() override; void OnShutdown() override; void OnStart() override; void OnStop() override; - void DoRemoteCommandsFetch() override; + void DoRemoteCommandsFetch(const syncer::Invalidation& invalidation) override; // CloudPolicyCore::Observer: void OnCoreConnected(CloudPolicyCore* core) override; @@ -39,8 +46,14 @@ void OnStoreError(CloudPolicyStore* store) override; private: + void RecordInvalidationMetric(const syncer::Invalidation& invalidation) const; + CloudPolicyCore* const core_; + const base::Clock* const clock_; + + const PolicyInvalidationScope scope_; + DISALLOW_COPY_AND_ASSIGN(RemoteCommandsInvalidatorImpl); };
diff --git a/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc b/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc index 6e63216c..026dff1 100644 --- a/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc +++ b/chrome/browser/policy/cloud/remote_commands_invalidator_unittest.cc
@@ -21,6 +21,14 @@ using ::testing::Mock; using ::testing::StrictMock; +namespace { + +MATCHER_P(InvalidationsEqual, expected_invalidation, "") { + return arg.Equals(expected_invalidation); +} + +} // namespace + namespace policy { class MockRemoteCommandInvalidator : public RemoteCommandsInvalidator { @@ -31,7 +39,7 @@ MOCK_METHOD0(OnShutdown, void()); MOCK_METHOD0(OnStart, void()); MOCK_METHOD0(OnStop, void()); - MOCK_METHOD0(DoRemoteCommandsFetch, void()); + MOCK_METHOD1(DoRemoteCommandsFetch, void(const syncer::Invalidation&)); void SetInvalidationTopic(const syncer::Topic& topic) { em::PolicyData policy_data; @@ -62,9 +70,12 @@ syncer::TRANSIENT_INVALIDATION_ERROR); } + syncer::Invalidation CreateInvalidation(const syncer::Topic& topic) { + return syncer::Invalidation::InitUnknownVersion(topic); + } + syncer::Invalidation FireInvalidation(const syncer::Topic& topic) { - const syncer::Invalidation invalidation = - syncer::Invalidation::InitUnknownVersion(topic); + const syncer::Invalidation invalidation = CreateInvalidation(topic); invalidation_service_.EmitInvalidationForTest(invalidation); return invalidation; } @@ -122,7 +133,10 @@ void VerifyInvalidationEnabled(const syncer::Topic& topic) { EXPECT_TRUE(invalidator_.invalidations_enabled()); - EXPECT_CALL(invalidator_, DoRemoteCommandsFetch()).Times(1); + EXPECT_CALL( + invalidator_, + DoRemoteCommandsFetch(InvalidationsEqual(CreateInvalidation(topic)))) + .Times(1); const syncer::Invalidation invalidation = FireInvalidation(topic); base::RunLoop().RunUntilIdle(); @@ -168,7 +182,9 @@ // Fire the invalidation, it should be acknowledged and trigger a remote // commands fetch. - EXPECT_CALL(invalidator_, DoRemoteCommandsFetch()).Times(1); + EXPECT_CALL(invalidator_, DoRemoteCommandsFetch(InvalidationsEqual( + CreateInvalidation(kTestingTopic1)))) + .Times(1); const syncer::Invalidation invalidation2 = FireInvalidation(kTestingTopic1); base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java index d8f4c64..fb43ab9 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -451,6 +451,9 @@ */ public static final String OFFLINE_INDICATOR_V2_ENABLED = "offline_indicator_v2_enabled"; + /** The shared preference for the 'save card to device' checkbox status. */ + public static final String PAYMENTS_CHECK_SAVE_CARD_TO_DEVICE = "check_save_card_to_device"; + /** Prefix of the preferences to persist use count of the payment instruments. */ public static final KeyPrefix PAYMENTS_PAYMENT_INSTRUMENT_USE_COUNT = new KeyPrefix("payment_instrument_use_count_*");
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java index 97ed6002c..9c9b20d 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java
@@ -125,6 +125,7 @@ ChromePreferenceKeys.OFFLINE_AUTO_FETCH_SHOWING_IN_PROGRESS, ChromePreferenceKeys.OFFLINE_AUTO_FETCH_USER_CANCEL_ACTION_IN_PROGRESS, ChromePreferenceKeys.OFFLINE_INDICATOR_V2_ENABLED, + ChromePreferenceKeys.PAYMENTS_CHECK_SAVE_CARD_TO_DEVICE, ChromePreferenceKeys.PAYMENTS_PAYMENT_COMPLETE_ONCE, ChromePreferenceKeys.PREFETCH_HAS_NEW_PAGES, ChromePreferenceKeys.PREFETCH_IGNORED_NOTIFICATION_COUNTER,
diff --git a/chrome/browser/previews/previews_browsertest.cc b/chrome/browser/previews/previews_browsertest.cc index a2a649d..ce8dd50 100644 --- a/chrome/browser/previews/previews_browsertest.cc +++ b/chrome/browser/previews/previews_browsertest.cc
@@ -439,3 +439,34 @@ EXPECT_FALSE(noscript_css_requested()); } } + +// This test class disables DataSaver. +class PreviewsDataSaverDisabledBrowserTest + : public PreviewsNoScriptBrowserTest { + public: + PreviewsDataSaverDisabledBrowserTest() = default; + + ~PreviewsDataSaverDisabledBrowserTest() override = default; + + void SetUpCommandLine(base::CommandLine* cmd) override { + PreviewsNoScriptBrowserTest::SetUpCommandLine(cmd); + cmd->RemoveSwitch("enable-spdy-proxy-auth"); + } +}; + +INSTANTIATE_TEST_SUITE_P(ShouldDisablePreview, + PreviewsDataSaverDisabledBrowserTest, + ::testing::Bool()); + +IN_PROC_BROWSER_TEST_P(PreviewsDataSaverDisabledBrowserTest, + NoPreviewWithDataSaverDisabled) { + base::HistogramTester histogram_tester; + ui_test_utils::NavigateToURL(browser(), https_url()); + + // Verify loaded noscript tag triggered js file and not css file. + EXPECT_TRUE(noscript_js_requested()); + EXPECT_FALSE(noscript_css_requested()); + + histogram_tester.ExpectTotalCount("OptimizationGuide.ApplyDecision.NoScript", + 0); +}
diff --git a/chrome/browser/previews/previews_service.cc b/chrome/browser/previews/previews_service.cc index c11154c..f0bf904 100644 --- a/chrome/browser/previews/previews_service.cc +++ b/chrome/browser/previews/previews_service.cc
@@ -21,6 +21,7 @@ #include "chrome/common/chrome_constants.h" #include "components/blacklist/opt_out_blacklist/opt_out_store.h" #include "components/blacklist/opt_out_blacklist/sql/opt_out_store_sql.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" #include "components/previews/content/previews_decider_impl.h" @@ -197,7 +198,10 @@ std::unique_ptr<previews::PreviewsOptimizationGuide> previews_opt_guide; OptimizationGuideKeyedService* optimization_guide_keyed_service = OptimizationGuideKeyedServiceFactory::GetForProfile(profile); - if (optimization_guide_keyed_service) { + if (optimization_guide_keyed_service && + data_reduction_proxy::DataReductionProxySettings:: + IsDataSaverEnabledByUser(profile->IsOffTheRecord(), + profile->GetPrefs())) { previews_opt_guide = std::make_unique<previews::PreviewsOptimizationGuide>( optimization_guide_keyed_service); }
diff --git a/chrome/browser/resources/chromeos/camera/src/js/metrics.js b/chrome/browser/resources/chromeos/camera/src/js/metrics.js index c1e2aac..8ff1ca4 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/metrics.js +++ b/chrome/browser/resources/chromeos/camera/src/js/metrics.js
@@ -5,6 +5,8 @@ import {browserProxy} from './browser_proxy/browser_proxy.js'; // eslint-disable-next-line no-unused-vars import {Intent} from './intent.js'; +// eslint-disable-next-line no-unused-vars +import {PerfEvent} from './perf.js'; import * as state from './state.js'; // eslint-disable-next-line no-unused-vars import {Facing} from './type.js'; @@ -141,15 +143,16 @@ /** * Returns event builder for the metrics type: perf. - * @param {string} event The target event type. + * @param {PerfEvent} event The target event type. * @param {number} duration The duration of the event in ms. * @param {Object=} extras Optional information for the event. * @return {!analytics.EventBuilder} */ function perfType(event, duration, extras = {}) { - const {resolution = ''} = extras; + const {resolution = '', facing = ''} = extras; return base.category('perf') .action(event) + .label(facing) // Round the duration here since GA expects that the value is an integer. // Reference: https://support.google.com/analytics/answer/1033068 .value(Math.round(duration))
diff --git a/chrome/browser/resources/chromeos/camera/src/js/perf.js b/chrome/browser/resources/chromeos/camera/src/js/perf.js index 289d637..02b1d457 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/perf.js +++ b/chrome/browser/resources/chromeos/camera/src/js/perf.js
@@ -12,6 +12,7 @@ */ export const PerfEvent = { PHOTO_TAKING: 'photo-taking', + PHOTO_CAPTURE_SHUTTER: 'photo-capture-shutter', PHOTO_CAPTURE_POST_PROCESSING: 'photo-capture-post-processing', VIDEO_CAPTURE_POST_PROCESSING: 'video-capture-post-processing', PORTRAIT_MODE_CAPTURE_POST_PROCESSING:
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js index 9be798b..480aeb0a 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
@@ -263,7 +263,8 @@ console.error(e); } finally { this.take_ = null; - state.set(state.State.TAKING, false, {hasError}); + state.set( + state.State.TAKING, false, {hasError, facing: this.facingMode_}); this.focus(); // Refocus the visible shutter button for ChromeVox. } })(); @@ -406,7 +407,8 @@ await this.preview_.start(stream); this.facingMode_ = await this.options_.updateValues(stream); await this.modes_.updateModeSelectionUI(deviceId); - await this.modes_.updateMode(mode, stream, deviceId, captureR); + await this.modes_.updateMode( + mode, stream, this.facingMode_, deviceId, captureR); nav.close(ViewName.WARNING, 'no-camera'); return true; } catch (e) {
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js index e05c505..71f7d84 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js
@@ -3,10 +3,11 @@ // found in the LICENSE file. import {assert, assertInstanceof} from '../../chrome_util.js'; -import {CaptureCandidate, // eslint-disable-line no-unused-vars - ConstraintsPreferrer, // eslint-disable-line no-unused-vars - PhotoConstraintsPreferrer, // eslint-disable-line no-unused-vars - VideoConstraintsPreferrer, // eslint-disable-line no-unused-vars +import { + CaptureCandidate, // eslint-disable-line no-unused-vars + ConstraintsPreferrer, // eslint-disable-line no-unused-vars + PhotoConstraintsPreferrer, // eslint-disable-line no-unused-vars + VideoConstraintsPreferrer, // eslint-disable-line no-unused-vars } from '../../device/constraints_preferrer.js'; import {Filenamer} from '../../models/filenamer.js'; import * as filesystem from '../../models/filesystem.js'; @@ -18,10 +19,14 @@ import * as sound from '../../sound.js'; import * as state from '../../state.js'; import * as toast from '../../toast.js'; -import {Resolution, - ResolutionList, // eslint-disable-line no-unused-vars +import { + Resolution, + ResolutionList, // eslint-disable-line no-unused-vars } from '../../type.js'; -import {Mode} from '../../type.js'; +import { + Facing, // eslint-disable-line no-unused-vars + Mode, +} from '../../type.js'; import * as util from '../../util.js'; import {RecordTime} from './recordtime.js'; @@ -176,6 +181,13 @@ this.stream_ = null; /** + * Camera facing of current mode. + * @type {!Facing} + * @private + */ + this.facing_ = Facing.UNKNOWN; + + /** * @type {!HTMLElement} * @private */ @@ -231,8 +243,8 @@ this.allModes_ = { [Mode.VIDEO]: { captureFactory: () => new Video( - assertInstanceof(this.stream_, MediaStream), createVideoSaver, - doSaveVideo), + assertInstanceof(this.stream_, MediaStream), this.facing_, + createVideoSaver, doSaveVideo), isSupported: async () => true, constraintsPreferrer: videoPreferrer, getV1Constraints: getV1Constraints.bind(this, true), @@ -241,8 +253,8 @@ }, [Mode.PHOTO]: { captureFactory: () => new Photo( - assertInstanceof(this.stream_, MediaStream), doSavePhoto, - this.captureResolution_, playShutterEffect), + assertInstanceof(this.stream_, MediaStream), this.facing_, + doSavePhoto, this.captureResolution_, playShutterEffect), isSupported: async () => true, constraintsPreferrer: photoPreferrer, getV1Constraints: getV1Constraints.bind(this, false), @@ -251,8 +263,8 @@ }, [Mode.SQUARE]: { captureFactory: () => new Square( - assertInstanceof(this.stream_, MediaStream), doSavePhoto, - this.captureResolution_, playShutterEffect), + assertInstanceof(this.stream_, MediaStream), this.facing_, + doSavePhoto, this.captureResolution_, playShutterEffect), isSupported: async () => true, constraintsPreferrer: photoPreferrer, getV1Constraints: getV1Constraints.bind(this, false), @@ -261,8 +273,8 @@ }, [Mode.PORTRAIT]: { captureFactory: () => new Portrait( - assertInstanceof(this.stream_, MediaStream), doSavePhoto, - this.captureResolution_, playShutterEffect), + assertInstanceof(this.stream_, MediaStream), this.facing_, + doSavePhoto, this.captureResolution_, playShutterEffect), isSupported: async (deviceId) => { if (deviceId === null) { return false; @@ -430,17 +442,19 @@ * Creates and updates new current mode object. * @param {!Mode} mode Classname of mode to be updated. * @param {!MediaStream} stream Stream of the new switching mode. + * @param {!Facing} facing Camera facing of the current mode. * @param {?string} deviceId Device id of currently working video device. * @param {?Resolution} captureResolution Capturing resolution width and * height. * @return {!Promise} */ - async updateMode(mode, stream, deviceId, captureResolution) { + async updateMode(mode, stream, facing, deviceId, captureResolution) { if (this.current !== null) { await this.current.stopCapture(); } this.updateModeUI_(mode); this.stream_ = stream; + this.facing_ = facing; this.captureResolution_ = captureResolution; this.current = this.allModes_[mode].captureFactory(); if (deviceId && this.captureResolution_) { @@ -493,10 +507,11 @@ class ModeBase { /** * @param {!MediaStream} stream + * @param {!Facing} facing * @param {?Resolution} captureResolution Capturing resolution width and * height. */ - constructor(stream, captureResolution) { + constructor(stream, facing, captureResolution) { /** * Stream of current mode. * @type {!MediaStream} @@ -505,6 +520,13 @@ this.stream_ = stream; /** + * Camera facing of current mode. + * @type {!Facing} + * @protected + */ + this.facing_ = facing; + + /** * Capture resolution. May be null on device not support of setting * resolution. * @type {?Resolution} @@ -579,11 +601,12 @@ class Video extends ModeBase { /** * @param {!MediaStream} stream + * @param {!Facing} facing * @param {!CreateVideoSaver} createVideoSaver * @param {!DoSaveVideo} doSaveVideo */ - constructor(stream, createVideoSaver, doSaveVideo) { - super(stream, null); + constructor(stream, facing, createVideoSaver, doSaveVideo) { + super(stream, facing, null); /** * @type {!CreateVideoSaver} @@ -662,7 +685,9 @@ try { await this.doSaveVideo_( {resolution, duration, videoSaver}, (new Filenamer()).newVideoName()); - state.set(PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false, {resolution}); + state.set( + PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false, + {resolution, facing: this.facing_}); } catch (e) { state.set( PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false, {hasError: true}); @@ -725,12 +750,14 @@ class Photo extends ModeBase { /** * @param {!MediaStream} stream + * @param {!Facing} facing * @param {!DoSavePhoto} doSavePhoto * @param {?Resolution} captureResolution * @param {!PlayShutterEffect} playShutterEffect */ - constructor(stream, doSavePhoto, captureResolution, playShutterEffect) { - super(stream, captureResolution); + constructor( + stream, facing, doSavePhoto, captureResolution, playShutterEffect) { + super(stream, facing, captureResolution); /** * Callback for saving picture. @@ -805,8 +832,11 @@ }); } + state.set(PerfEvent.PHOTO_CAPTURE_SHUTTER, true); try { const results = await this.crosImageCapture_.takePhoto(photoSettings); + + state.set(PerfEvent.PHOTO_CAPTURE_SHUTTER, false, {facing: this.facing_}); this.playShutterEffect_(); state.set(PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, true); @@ -814,8 +844,11 @@ const image = await util.blobToImage(blob); const resolution = new Resolution(image.width, image.height); await this.doSavePhoto_({resolution, blob}, imageName); - state.set(PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false, {resolution}); + state.set( + PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false, + {resolution, facing: this.facing_}); } catch (e) { + state.set(PerfEvent.PHOTO_CAPTURE_SHUTTER, false, {hasError: true}); state.set( PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false, {hasError: true}); toast.show('error_msg_take_photo_failed'); @@ -901,12 +934,14 @@ class Square extends Photo { /** * @param {!MediaStream} stream + * @param {!Facing} facing * @param {!DoSavePhoto} doSavePhoto * @param {?Resolution} captureResolution * @param {!PlayShutterEffect} playShutterEffect */ - constructor(stream, doSavePhoto, captureResolution, playShutterEffect) { - super(stream, doSavePhoto, captureResolution, playShutterEffect); + constructor( + stream, facing, doSavePhoto, captureResolution, playShutterEffect) { + super(stream, facing, doSavePhoto, captureResolution, playShutterEffect); this.doSavePhoto_ = async (result, ...args) => { // Since the image blob after square cut will lose its EXIF including @@ -948,12 +983,14 @@ class Portrait extends Photo { /** * @param {!MediaStream} stream + * @param {!Facing} facing * @param {!DoSavePhoto} doSavePhoto * @param {?Resolution} captureResolution * @param {!PlayShutterEffect} playShutterEffect */ - constructor(stream, doSavePhoto, captureResolution, playShutterEffect) { - super(stream, doSavePhoto, captureResolution, playShutterEffect); + constructor( + stream, facing, doSavePhoto, captureResolution, playShutterEffect) { + super(stream, facing, doSavePhoto, captureResolution, playShutterEffect); } /** @@ -1036,6 +1073,7 @@ } await refSave; state.set( - PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, false, {hasError}); + PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, false, + {hasError, facing: this.facing_}); } }
diff --git a/chrome/browser/resources/settings/autofill_page/password_check.html b/chrome/browser/resources/settings/autofill_page/password_check.html index 55c527a..005dee6 100644 --- a/chrome/browser/resources/settings/autofill_page/password_check.html +++ b/chrome/browser/resources/settings/autofill_page/password_check.html
@@ -9,6 +9,7 @@ <link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="password_check_list_item.html"> <link rel="import" href="password_manager_proxy.html"> @@ -43,6 +44,16 @@ } </style> + <!-- The banner is visible if no compromised password was found (yet). --> + <template is="dom-if" if="[[shouldShowBanner_(status_, leakedPasswords)]]"> + <picture> + <source srcset="[[bannerImageSrc_(1, status_)]]" + media="(prefers-color-scheme: dark)"> + <img id="bannerImage" src="[[bannerImageSrc_(0, status_)]]"> + </picture> + </template> + + <!-- The header showing progress or result of the check--> <div class="settings-box first two-line" id="leakCheckHeader"> <!-- If the password check concluded, show only a status Icon. --> <template is="dom-if" if="[[!isCheckInProgress_(status_)]]">
diff --git a/chrome/browser/resources/settings/autofill_page/password_check.js b/chrome/browser/resources/settings/autofill_page/password_check.js index d434176..6937b5d 100644 --- a/chrome/browser/resources/settings/autofill_page/password_check.js +++ b/chrome/browser/resources/settings/autofill_page/password_check.js
@@ -189,7 +189,7 @@ * @param {!PasswordManagerProxy.PasswordCheckStatus} status * @param {!Array<!PasswordManagerProxy.CompromisedCredential>} * leakedPasswords - * @return {!string} + * @return {string} * @private */ getStatusIcon_(status, leakedPasswords) { @@ -207,7 +207,7 @@ * @param {!PasswordManagerProxy.PasswordCheckStatus} status * @param {!Array<!PasswordManagerProxy.CompromisedCredential>} * leakedPasswords - * @return {!string} + * @return {string} * @private */ getStatusIconClass_(status, leakedPasswords) { @@ -333,6 +333,31 @@ }, /** + * Returns the chrome:// address where the banner image is located. + * @param {boolean} isDarkMode + * @return {string} + * @private + */ + bannerImageSrc_(isDarkMode) { + const type = this.status_.state == CheckState.IDLE ? 'positive' : 'neutral'; + const suffix = isDarkMode ? '_dark' : ''; + return `chrome://settings/images/password_check_${type}${suffix}.svg`; + }, + + /** + * Returns true iff the banner should be shown. + * @return {boolean} + * @private + */ + shouldShowBanner_() { + if (this.hasLeakedCredentials_(this.leakedPasswords)) { + return false; + } + return this.status_.state == CheckState.CANCELED || + !this.hasLeaksOrErrors_(this.status_, this.leakedPasswords); + }, + + /** * Returns true if there are leaked credentials or the status is unexpected * for a regular password check. * @param {!PasswordManagerProxy.PasswordCheckStatus} status
diff --git a/chrome/browser/resources/settings/autofill_page/password_check_list_item.html b/chrome/browser/resources/settings/autofill_page/password_check_list_item.html index 680b3da..0f6d86b 100644 --- a/chrome/browser/resources/settings/autofill_page/password_check_list_item.html +++ b/chrome/browser/resources/settings/autofill_page/password_check_list_item.html
@@ -13,12 +13,6 @@ <dom-module id="password-check-list-item"> <template> <style include="settings-shared passwords-shared"> - .icon-column { - align-items: center; - height: 16px; - margin-inline-end: 16px; - } - #change-password-link-icon { height: 16px; margin-inline-start: 10px; @@ -26,15 +20,10 @@ --iron-icon-fill-color: var(--text-color-action); } - #icon-more-vert { - height: 32px; - width: 32px; - } - #leakedPassword { background-color: transparent; border: none; - color: inherit; + margin-inline-start: 4px; } #leaked-item { @@ -43,39 +32,77 @@ } #leaked-info { + display: flex; + flex: 2; + width: 0; + } + + #leakUsername { + align-items: center; + display: flex; flex: 1; } - </style> - <div class="list-item" id="leaked-item"> - <div class="icon-column"> - <site-favicon url="[[item.changePasswordUrl]]"></site-favicon> - </div> - <div class="info-column two-line" id="leaked-info"> - <div class="start text"> - <div id="leakOrigin">[[item.formattedOrigin]]</div> - <div> - <span class="secondary" id="leakUsername">[[item.username]]</span> - <input id="leakedPassword" type="password" value="[[password_]]" - readonly disabled> + #changePasswordInApp { + display: flex; + flex: 2; + flex-direction: row-reverse; + } + + #changePasswordUrl { + display: flex; + flex: 1; + flex-direction: row-reverse; + white-space: nowrap; + } + + #info-column { + display: flex; + flex: 1; + flex-direction: column; + } + + #leakOrigin { + direction: rtl; + display: flex; + justify-content: flex-end; + } + </style> + <div class="list-item" id="leaked-item" focus-row-container> + <site-favicon url="[[item.changePasswordUrl]]"></site-favicon> + <div id="leaked-info"> + <div id="info-column" class="no-min-width"> + <div id="leakOrigin" class="no-min-width"> + <span class="text-elide"> + <!-- This bdo tag is necessary to fix the display of domains + starting with numbers. --> + <bdo dir="ltr">[[item.formattedOrigin]]</bdo> + </span> </div> - <div class="secondary" - id="leakType">[[getCompromiseType_(item)]] + <div class="no-min-width" id="leakUsername" > + <span class="no-min-width text-elide secondary"> + [[item.username]] + </span> + <input class="no-min-width secondary" id="leakedPassword" + type="password" value="[[password_]]" readonly disabled> </div> - <div class="secondary" - id="elapsedTime">[[item.elapsedTimeSinceCompromise]] + <div class="secondary" id="leakType"> + [[getCompromiseType_(item)]] + </div> + <div class="secondary" id="elapsedTime"> + [[item.elapsedTimeSinceCompromise]] </div> </div> </div> <template is="dom-if" if="[[item.changePasswordUrl]]"> <div class="button-container" id="changePasswordUrl"> - <!-- TODO:(https://crbug.com/1047726) add 'Already changed this password?' link --> - <cr-button class="action-button" on-click="onChangePasswordClick_"> - $i18n{changePasswordButton} - <iron-icon icon="cr:open-in-new" id="change-password-link-icon"> - </iron-icon> - </cr-button> - </div> + <!-- TODO:(https://crbug.com/1047726) add 'Already changed this password?' link --> + <cr-button class="action-button" on-click="onChangePasswordClick_"> + $i18n{changePasswordButton} + <iron-icon icon="cr:open-in-new" id="change-password-link-icon"> + </iron-icon> + </cr-button> + </div> </template> <template is="dom-if" if="[[!item.changePasswordUrl]]"> <span id="changePasswordInApp">$i18n{changePasswordInApp}</span>
diff --git a/chrome/browser/resources/settings/images/password_check_positive.svg b/chrome/browser/resources/settings/images/password_check_positive.svg new file mode 100644 index 0000000..6e3eeaa --- /dev/null +++ b/chrome/browser/resources/settings/images/password_check_positive.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="680" height="120"><style>.B{mask:url(#B)}.C{fill:#bdc0c5}.D{fill:#e8e9eb}.E{fill:#f8f9fa}.F{fill-rule:nonzero}</style><defs><path id="A" d="M0 0h680v120H0z"/></defs><g fill-rule="evenodd"><mask id="B" fill="#fff"><use xlink:href="#A"/></mask><use fill-opacity=".02" xlink:href="#A"/><g class="F B"><path d="M288.585 52.215V47c10.735 0 19.175-3 25.1-8.955 9.3-9.36 9.325-23.015 9.325-23.15l5.25-.04c0 .645 0 15.9-10.815 26.82-6.935 6.995-16.645 10.54-28.85 10.54z" class="D"/><path d="M253.87 83h-5.245a40.45 40.45 0 0 1 5-18c4.605-8.2 14.4-18 34.96-18v5.215c-14.465 0-24.685 5.17-30.385 15.36A35.35 35.35 0 0 0 253.87 83z" fill="#34a751"/><path d="M56 57.915H38.175v-.27a8.91 8.91 0 1 1 17.82 0l.005.27zm-17.275-.54H55.45a8.37 8.37 0 0 0-16.73 0h.005z" class="C"/><g class="D"><path d="M426.825 68.895h-17.28a8.64 8.64 0 0 1 17.28 0zM345 88.66h20v4h-20z"/><path d="M348.268 98.32l10-17.32 3.464 2-10 17.32z"/><path d="M358.268 100.32l-10-17.32 3.464-2 10 17.32z"/></g><path d="M254.6 94.5h-90.7V32.325a2.65 2.65 0 0 1 2.64-2.64h85.44a2.65 2.65 0 0 1 2.64 2.64V94.5z" class="E"/><path d="M250.3 30.225A3.791 3.791 0 0 1 254.08 34v59.945h-89.64V34a3.786 3.786 0 0 1 3.78-3.78h82.08m0-.54h-82.1a4.335 4.335 0 0 0-4.32 4.32v60.5h90.72V34a4.335 4.335 0 0 0-4.32-4.32zm-99.36 68.585h116.64v.54H150.93v-.54z" class="C"/><g stroke="#bdc0c5" stroke-width=".5" class="E"><rect x="112" y="18" width="68" height="92" rx="6"/><path d="M224.75 55.75h-76.5a2.43 2.43 0 0 0-1.773.783 2.725 2.725 0 0 0-.727 1.867v19.2c.001.73.28 1.39.727 1.867.454.484 1.08.782 1.772.783h76.5a2.43 2.43 0 0 0 1.773-.783 2.725 2.725 0 0 0 .727-1.867V58.4a2.73 2.73 0 0 0-.727-1.867 2.426 2.426 0 0 0-1.772-.783z"/></g><g fill="#3a7bee"><rect x="215" y="62" width="2" height="12" rx="1"/><path d="M171 67h10v2h-10z"/><path d="M172.634 71.83l5-8.66 1.732 1-5 8.66z"/><path d="M177.634 72.83l-5-8.66 1.732-1 5 8.66zM185 67h10v2h-10z"/><path d="M186.634 71.83l5-8.66 1.732 1-5 8.66z"/><path d="M191.634 72.83l-5-8.66 1.732-1 5 8.66zM199 67h10v2h-10z"/><path d="M200.634 71.83l5-8.66 1.732 1-5 8.66z"/><path d="M205.634 72.83l-5-8.66 1.732-1 5 8.66z"/></g></g><circle fill="#34a751" cx="146" cy="68" r="20" class="B"/><path fill="#fff" d="M143.214 74.75l-6.964-6.478 1.964-1.827 5 4.638 10.572-9.833 1.964 1.84z" class="B"/><g class="F B"><g stroke="#bdc0c5" stroke-width=".5" class="E"><path d="M146 10h0a7 7 0 0 1 7 7v7h-14v-7a7 7 0 0 1 7-7z"/><circle cx="146" cy="17" r="3"/><path d="M162 24h-32a6 6 0 0 0-6 6v4h44v-4a6 6 0 0 0-6-6z"/></g><path d="M79.6 58.42a12.935 12.935 0 0 0-10.1 4.82A8.62 8.62 0 0 0 58 71.38h34.56c0-7.158-5.802-12.96-12.96-12.96z" fill="#fff"/><path d="M92.83 71.65h-35.1v-.27a8.89 8.89 0 0 1 11.695-8.455A13.23 13.23 0 0 1 92.83 71.38v.27zm-34.555-.54h34a12.69 12.69 0 0 0-22.56-7.7l-.12.15-.18-.065A8.35 8.35 0 0 0 58.26 71.11h.015z" class="C"/><path d="M38.12 82.36l3.705-3.705c7.6 7.6 15.7 11.43 24.075 11.4 13.17-.03 22.855-9.655 22.95-9.75L92.585 84c-.45.46-11.235 11.25-26.6 11.315C56.12 95.345 46.75 91 38.12 82.36z" fill="#f7bb2a"/><path d="M-8.2 79.58l-3.705-3.705a40.45 40.45 0 0 1 16.25-9.18c9.075-2.57 22.945-2.58 37.5 11.96L38.14 82.36C27.9 72.13 17 68.555 5.77 71.735A35.342 35.342 0 0 0-8.2 79.58z" class="D"/><g class="C"><path d="M636.62 39.735c-5.777.008-10.613-4.377-11.168-10.127s3.35-10.98 9.022-12.08 11.248 2.294 12.88 7.835a11.205 11.205 0 0 1-10.733 14.37zm0-21.765a10.58 10.58 0 0 0-9.82 14.5 10.57 10.57 0 0 0 20.298-5.263 10.57 10.57 0 0 0-10.478-9.237zM619 130h-80a6.785 6.785 0 0 1-6.775-6.775v-10h.6v10A6.185 6.185 0 0 0 539 129.38h80a6.185 6.185 0 0 0 6.175-6.175v-43.55A6.185 6.185 0 0 0 619 73.5h-12v-.6h12a6.785 6.785 0 0 1 6.775 6.775V123.2A6.784 6.784 0 0 1 619 130z"/><path d="M607.005 73.48H561l3-.6h43.005z"/><path d="M532.8 100.18h-.6v-20.5a6.78 6.78 0 0 1 6.8-6.8h29.5v.62H539a6.185 6.185 0 0 0-6.175 6.175l-.025 20.505z"/></g><path d="M540 93.28a14.37 14.37 0 0 0-11.205 5.355A9.58 9.58 0 0 0 516 107.68h38.4c0-7.953-6.447-14.4-14.4-14.4z" fill="#fff"/><path d="M554.725 108h-39v-.3a9.88 9.88 0 0 1 13-9.395 14.7 14.7 0 0 1 26 9.395v.3zm-38.395-.6h37.795a14.1 14.1 0 0 0-25.065-8.555l-.135.165-.2-.07c-2.795-.998-5.898-.598-8.35 1.075s-3.953 4.42-4.04 7.385h-.005z" class="C"/><path d="M498.67 29.88L534.33-.525" class="E"/><path d="M498.32 29.468L534-.9l.65.762-35.68 30.377-.648-.76zM641.43 56.08h-5.825a44.942 44.942 0 0 0 5.555 20c5.1 9.145 16 20.05 38.84 20.05V90.3c-16.07 0-27.43-5.745-33.76-17.07a39.127 39.127 0 0 1-4.8-17.14z" class="D"/></g></g></svg> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/images/password_check_positive_dark.svg b/chrome/browser/resources/settings/images/password_check_positive_dark.svg new file mode 100644 index 0000000..8474160 --- /dev/null +++ b/chrome/browser/resources/settings/images/password_check_positive_dark.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="680" height="120"><style>.B{mask:url(#B)}.C{fill:#414447}.D{stroke:#4e5154}.E{stroke-width:.5}.F{fill:#262628}.G{fill-rule:nonzero}</style><defs><path id="A" d="M0 0h680v120H0z"/></defs><g fill-rule="evenodd"><mask id="B" fill="#fff"><use xlink:href="#A"/></mask><use fill-opacity=".1" xlink:href="#A"/><g class="G B"><path d="M288.585 52.215V47c10.735 0 19.175-3 25.1-8.955 9.3-9.36 9.325-23.015 9.325-23.15l5.25-.04c0 .645 0 15.9-10.815 26.82-6.935 6.995-16.645 10.54-28.85 10.54z" class="C"/><path d="M253.87 83h-5.245a40.45 40.45 0 0 1 5-18c4.605-8.2 14.4-18 34.96-18v5.215c-14.465 0-24.685 5.17-30.385 15.36A35.35 35.35 0 0 0 253.87 83z" fill="#81c995"/><g class="C"><path d="M56 57.915H38.175v-.27a8.91 8.91 0 1 1 17.82 0l.005.27zm-17.275-.54H55.45a8.37 8.37 0 0 0-16.73 0h.005zm388.1 11.52h-17.28a8.64 8.64 0 0 1 17.28 0zM345 88.66h20v4h-20z"/><path d="M348.268 98.32l10-17.32 3.464 2-10 17.32z"/><path d="M358.268 100.32l-10-17.32 3.464-2 10 17.32z"/></g><path d="M254.6 94.5h-90.7V32.325a2.65 2.65 0 0 1 2.64-2.64h85.44a2.65 2.65 0 0 1 2.64 2.64V94.5z" class="D E F"/><path d="M250.3 30.225A3.791 3.791 0 0 1 254.08 34v59.945h-89.64V34a3.786 3.786 0 0 1 3.78-3.78h82.08m0-.54h-82.1a4.335 4.335 0 0 0-4.32 4.32v60.5h90.72V34a4.335 4.335 0 0 0-4.32-4.32zm-99.36 68.585h116.64v.54H150.93v-.54z" class="C"/><g class="D E F"><rect x="112" y="18" width="68" height="92" rx="6"/><path d="M224.75 56c1.242.002 2.25 1.075 2.25 2.4v19.2c-.001 1.325-1.008 2.398-2.25 2.4h-76.5c-1.242-.002-2.25-1.075-2.25-2.4V58.4c.001-1.325 1.008-2.398 2.25-2.4h76.5z"/></g><g fill="#8ab4f8"><rect x="215" y="62" width="2" height="12" rx="1"/><path d="M171 67h10v2h-10z"/><path d="M172.634 71.83l5-8.66 1.732 1-5 8.66z"/><path d="M177.634 72.83l-5-8.66 1.732-1 5 8.66zM185 67h10v2h-10z"/><path d="M186.634 71.83l5-8.66 1.732 1-5 8.66z"/><path d="M191.634 72.83l-5-8.66 1.732-1 5 8.66zM199 67h10v2h-10z"/><path d="M200.634 71.83l5-8.66 1.732 1-5 8.66z"/><path d="M205.634 72.83l-5-8.66 1.732-1 5 8.66z"/></g><circle fill="#81c995" cx="146" cy="68" r="20"/></g><path fill="#28282b" d="M143.214 74.75l-6.964-6.478 1.964-1.827 5 4.638 10.572-9.833 1.964 1.84z" class="B"/><g class="G B"><g class="D E F"><path d="M146 10a7 7 0 0 1 7 7v7h-14v-7a7 7 0 0 1 7-7z"/><circle cx="146" cy="17" r="3"/><path d="M162 24h-32a6 6 0 0 0-6 6v4h44v-4a6 6 0 0 0-6-6z"/></g><path d="M79.6 58.42a12.935 12.935 0 0 0-10.1 4.82A8.62 8.62 0 0 0 58 71.38h34.56c0-7.158-5.802-12.96-12.96-12.96z" class="C"/><path d="M92.83 71.65h-35.1v-.27a8.89 8.89 0 0 1 11.695-8.455A13.23 13.23 0 0 1 92.83 71.38v.27zm-34.555-.54h34a12.69 12.69 0 0 0-22.56-7.7l-.12.15-.18-.065A8.35 8.35 0 0 0 58.26 71.11h.015z" fill="#bdc0c5"/><path d="M38.12 82.36l3.705-3.705c7.6 7.6 15.7 11.43 24.075 11.4 13.17-.03 22.855-9.655 22.95-9.75L92.585 84c-.45.46-11.235 11.25-26.6 11.315C56.12 95.345 46.75 91 38.12 82.36z" fill="#f7bb2a"/><path d="M-8.2 79.58l-3.705-3.705a40.45 40.45 0 0 1 16.25-9.18c9.075-2.57 22.945-2.58 37.5 11.96L38.14 82.36C27.9 72.13 17 68.555 5.77 71.735A35.342 35.342 0 0 0-8.2 79.58z" class="C"/><path d="M636.62 39.735c-5.777.008-10.613-4.377-11.168-10.127s3.35-10.98 9.022-12.08 11.248 2.294 12.88 7.835a11.205 11.205 0 0 1-10.733 14.37zm0-21.765a10.58 10.58 0 0 0-9.82 14.5 10.57 10.57 0 0 0 20.298-5.263 10.57 10.57 0 0 0-10.478-9.237zM619 130h-80a6.785 6.785 0 0 1-6.775-6.775v-10h.6v10A6.185 6.185 0 0 0 539 129.38h80a6.185 6.185 0 0 0 6.175-6.175v-43.55A6.185 6.185 0 0 0 619 73.5h-12v-.6h12a6.785 6.785 0 0 1 6.775 6.775V123.2A6.784 6.784 0 0 1 619 130z" fill="#4e5154"/><path d="M607.005 73.48H561l3-.6h43.005z" class="D E F"/><path d="M532.8 100.18h-.6v-20.5a6.78 6.78 0 0 1 6.8-6.8h29.5v.62H539a6.185 6.185 0 0 0-6.175 6.175l-.025 20.505z" fill="#bdc0c5"/><path d="M540 93.28a14.37 14.37 0 0 0-11.205 5.355A9.58 9.58 0 0 0 516 107.68h38.4c0-7.953-6.447-14.4-14.4-14.4z" class="C"/><path d="M554.725 108h-39v-.3a9.88 9.88 0 0 1 13-9.395 14.7 14.7 0 0 1 26 9.395v.3zm-38.395-.6h37.795a14.1 14.1 0 0 0-25.065-8.555l-.135.165-.2-.07c-2.795-.998-5.898-.598-8.35 1.075s-3.953 4.42-4.04 7.385h-.005z" fill="#4e5154"/><path d="M498.67 29.88L534.33-.525m-36.01 29.993L534-.9l.65.762-35.68 30.377-.648-.76zM641.43 56.08h-5.825a44.942 44.942 0 0 0 5.555 20c5.1 9.145 16 20.05 38.84 20.05V90.3c-16.07 0-27.43-5.745-33.76-17.07a39.127 39.127 0 0 1-4.8-17.14z"/></g></g></svg> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/people_page/sync_controls.js b/chrome/browser/resources/settings/people_page/sync_controls.js index 795d5b4..563dfea 100644 --- a/chrome/browser/resources/settings/people_page/sync_controls.js +++ b/chrome/browser/resources/settings/people_page/sync_controls.js
@@ -39,7 +39,7 @@ Polymer({ is: 'settings-sync-controls', - behaviors: [WebUIListenerBehavior], + behaviors: [WebUIListenerBehavior, settings.RouteObserverBehavior], properties: { hidden: { @@ -103,6 +103,14 @@ } }, + /** @protected */ + currentRouteChanged() { + const router = settings.Router.getInstance(); + if (router.getCurrentRoute() === router.getRoutes().SYNC_ADVANCED) { + chrome.metricsPrivate.recordUserAction('Sync_NavigateToSyncAdvancedPage'); + } + }, + /** * Handler for when the sync preferences are updated. * @private
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index c29249e..8af18dc6 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -673,6 +673,12 @@ <structure name="IDR_SETTINGS_IMAGES_PASSWORD_CHECK_NEUTRAL_DARK_SVG" file="images/password_check_neutral_dark.svg" type="chrome_html" /> + <structure name="IDR_SETTINGS_IMAGES_PASSWORD_CHECK_POSITIVE_SVG" + file="images/password_check_positive.svg" + type="chrome_html" /> + <structure name="IDR_SETTINGS_IMAGES_PASSWORD_CHECK_POSITIVE_DARK_SVG" + file="images/password_check_positive_dark.svg" + type="chrome_html" /> <structure name="IDR_SETTINGS_PASSWORDS_SECTION_HTML" file="autofill_page/passwords_section.html" type="chrome_html"
diff --git a/chrome/browser/resources/settings/settings_resources_vulcanized.grd b/chrome/browser/resources/settings/settings_resources_vulcanized.grd index 19e6cbed..84d4f2f 100644 --- a/chrome/browser/resources/settings/settings_resources_vulcanized.grd +++ b/chrome/browser/resources/settings/settings_resources_vulcanized.grd
@@ -60,6 +60,14 @@ file="images/password_check_neutral_dark.svg" type="BINDATA" compress="gzip" /> + <include name="IDR_SETTINGS_IMAGES_PASSWORD_CHECK_POSITIVE_SVG" + file="images/password_check_positive.svg" + type="BINDATA" + compress="gzip" /> + <include name="IDR_SETTINGS_IMAGES_PASSWORD_CHECK_POSITIVE_DARK_SVG" + file="images/password_check_positive_dark.svg" + type="BINDATA" + compress="gzip" /> <!-- Polymer 3 related files --> <include name="IDR_SETTINGS_SETTINGS_V3_HTML" file="settings_v3.html"
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index 42cacbd..edfa60b 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -163,8 +163,6 @@ "download_protection/download_feedback.h", "download_protection/download_feedback_service.cc", "download_protection/download_feedback_service.h", - "download_protection/download_item_request.cc", - "download_protection/download_item_request.h", "download_protection/download_protection_service.cc", "download_protection/download_protection_service.h", "download_protection/download_protection_util.cc",
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.cc index 28cf2dd..2dc937c 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.cc +++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.cc
@@ -538,15 +538,11 @@ } // Create a file request for each file. - for (size_t i = 0; i < data_.paths.size(); ++i) { - if (FileTypeSupported(data_.do_malware_scan, data_.do_dlp_scan, - data_.paths[i])) { - PrepareFileRequest( - data_.paths[i], - base::BindOnce(&DeepScanningDialogDelegate::AnalyzerCallback, - weak_ptr_factory_.GetWeakPtr(), i)); + for (const base::FilePath& path : data_.paths) { + if (FileTypeSupported(data_.do_malware_scan, data_.do_dlp_scan, path)) { + PrepareFileRequest(path); } else { - FileRequestCallback(data_.paths[i], + FileRequestCallback(path, BinaryUploadService::Result::UNSUPPORTED_FILE_TYPE, DeepScanningClientResponse()); } @@ -555,48 +551,15 @@ return !text_request_complete_ || file_result_count_ != data_.paths.size(); } -void DeepScanningDialogDelegate::PrepareFileRequest(base::FilePath path, - AnalyzeCallback callback) { - base::FilePath::StringType ext(path.FinalExtension()); - std::transform(ext.begin(), ext.end(), ext.begin(), tolower); - if (ext == FILE_PATH_LITERAL(".zip")) { - auto analyzer = base::MakeRefCounted<SandboxedZipAnalyzer>( - path, std::move(callback), LaunchFileUtilService()); - analyzer->Start(); - } else if (ext == FILE_PATH_LITERAL(".rar")) { - auto analyzer = base::MakeRefCounted<SandboxedRarAnalyzer>( - path, std::move(callback), LaunchFileUtilService()); - analyzer->Start(); - } else { - std::move(callback).Run(safe_browsing::ArchiveAnalyzerResults()); - } -} - -void DeepScanningDialogDelegate::AnalyzerCallback( - int index, - const safe_browsing::ArchiveAnalyzerResults& results) { - bool contains_encrypted_parts = std::any_of( - results.archived_binary.begin(), results.archived_binary.end(), - [](const auto& binary) { return binary.is_encrypted(); }); - - // If the file contains encrypted parts and the user is not allowed to use - // them, fail the request. - if (contains_encrypted_parts) { - FileRequestCallback(data_.paths[index], - BinaryUploadService::Result::FILE_ENCRYPTED, - DeepScanningClientResponse()); - return; - } - +void DeepScanningDialogDelegate::PrepareFileRequest(base::FilePath path) { auto request = std::make_unique<FileSourceRequest>( - data_.paths[index], - base::BindOnce(&DeepScanningDialogDelegate::FileRequestCallback, - weak_ptr_factory_.GetWeakPtr(), data_.paths[index])); + path, base::BindOnce(&DeepScanningDialogDelegate::FileRequestCallback, + weak_ptr_factory_.GetWeakPtr(), path)); FileSourceRequest* request_raw = request.get(); - request_raw->GetRequestData(base::BindOnce( - &DeepScanningDialogDelegate::OnGotFileInfo, - weak_ptr_factory_.GetWeakPtr(), std::move(request), data_.paths[index])); + request_raw->GetRequestData( + base::BindOnce(&DeepScanningDialogDelegate::OnGotFileInfo, + weak_ptr_factory_.GetWeakPtr(), std::move(request), path)); } void DeepScanningDialogDelegate::PrepareRequest(
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h index bc2503e..083152fa 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h +++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h
@@ -248,8 +248,7 @@ // Prepares an upload request for the file at |path|. If the file // cannot be uploaded it will have a failure verdict added to |result_|. // Virtual so that it can be overridden in tests. - virtual void PrepareFileRequest(base::FilePath path, - AnalyzeCallback callback); + virtual void PrepareFileRequest(base::FilePath path); // Prepares an upload request for the given file. void AnalyzerCallback(int index,
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.cc b/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.cc index d080e7bb..9198435 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.cc +++ b/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.cc
@@ -137,20 +137,14 @@ DeepScanningClientResponse response = status_callback_.is_null() ? DeepScanningClientResponse() : status_callback_.Run(path); - if (path.empty()) + if (path.empty()) { StringRequestCallback(result_, response); - else + } else if (encryption_callback_.Run(path)) { + FileRequestCallback(path, BinaryUploadService::Result::FILE_ENCRYPTED, + response); + } else { FileRequestCallback(path, result_, response); -} - -void FakeDeepScanningDialogDelegate::PrepareFileRequest( - base::FilePath path, - AnalyzeCallback callback) { - safe_browsing::ArchiveAnalyzerResults results; - if (!encryption_callback_.is_null() && encryption_callback_.Run(path)) - results.archived_binary.Add()->set_is_encrypted(true); - - std::move(callback).Run(results); + } } void FakeDeepScanningDialogDelegate::UploadTextForDeepScanning(
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.h b/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.h index 347f399..7dff16b3 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.h +++ b/chrome/browser/safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.h
@@ -95,8 +95,6 @@ std::unique_ptr<BinaryUploadService::Request> request); // DeepScanningDialogDelegate overrides. - void PrepareFileRequest(base::FilePath path, - AnalyzeCallback callback) override; void UploadTextForDeepScanning( std::unique_ptr<BinaryUploadService::Request> request) override; void UploadFileForDeepScanning(
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request.cc b/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request.cc index e548ff5..40c4021 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request.cc +++ b/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request.cc
@@ -6,7 +6,11 @@ #include "base/strings/string_number_conversions.h" #include "base/task/post_task.h" +#include "chrome/browser/file_util_service.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h" +#include "chrome/common/safe_browsing/archive_analyzer_results.h" +#include "chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h" +#include "chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.h" #include "crypto/secure_hash.h" #include "crypto/sha2.h" @@ -109,14 +113,52 @@ weakptr_factory_.GetWeakPtr(), std::move(callback))); } +void FileSourceRequest::OnArchiveAnalysisComplete( + DataCallback callback, + std::pair<BinaryUploadService::Result, Data> result_and_data, + const ArchiveAnalyzerResults& results) { + has_cached_result_ = true; + set_digest(result_and_data.second.hash); + contains_encrypted_parts_ = std::any_of( + results.archived_binary.begin(), results.archived_binary.end(), + [](const auto& binary) { return binary.is_encrypted(); }); + + if (contains_encrypted_parts_) + cached_result_ = BinaryUploadService::Result::FILE_ENCRYPTED; + else + cached_result_ = result_and_data.first; + + cached_data_ = result_and_data.second; + std::move(callback).Run(cached_result_, cached_data_); +} + void FileSourceRequest::OnGotFileData( DataCallback callback, std::pair<BinaryUploadService::Result, Data> result_and_data) { - set_digest(result_and_data.second.hash); - has_cached_result_ = true; - cached_result_ = result_and_data.first; - cached_data_ = result_and_data.second; - std::move(callback).Run(result_and_data.first, result_and_data.second); + if (result_and_data.first != BinaryUploadService::Result::SUCCESS) { + OnArchiveAnalysisComplete(std::move(callback), std::move(result_and_data), + ArchiveAnalyzerResults()); + return; + } + + base::OnceCallback<void(const ArchiveAnalyzerResults& results)> + analysis_callback = + base::BindOnce(&FileSourceRequest::OnArchiveAnalysisComplete, + weakptr_factory_.GetWeakPtr(), std::move(callback), + std::move(result_and_data)); + base::FilePath::StringType ext(path_.FinalExtension()); + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); + if (ext == FILE_PATH_LITERAL(".zip")) { + auto analyzer = base::MakeRefCounted<SandboxedZipAnalyzer>( + path_, std::move(analysis_callback), LaunchFileUtilService()); + analyzer->Start(); + } else if (ext == FILE_PATH_LITERAL(".rar")) { + auto analyzer = base::MakeRefCounted<SandboxedRarAnalyzer>( + path_, std::move(analysis_callback), LaunchFileUtilService()); + analyzer->Start(); + } else { + std::move(analysis_callback).Run(ArchiveAnalyzerResults()); + } } } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request.h b/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request.h index b79f079..697147a 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request.h +++ b/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_SAFE_BROWSING_CLOUD_CONTENT_SCANNING_FILE_SOURCE_REQUEST_H_ #include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h" +#include "chrome/common/safe_browsing/archive_analyzer_results.h" namespace safe_browsing { @@ -28,7 +29,13 @@ DataCallback callback, std::pair<BinaryUploadService::Result, Data> result_and_data); + void OnArchiveAnalysisComplete( + DataCallback callback, + std::pair<BinaryUploadService::Result, Data> result_and_data, + const ArchiveAnalyzerResults& results); + bool has_cached_result_; + bool contains_encrypted_parts_; BinaryUploadService::Result cached_result_; Data cached_data_;
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request_unittest.cc index 62284a8..e097f1f 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request_unittest.cc +++ b/chrome/browser/safe_browsing/cloud_content_scanning/file_source_request_unittest.cc
@@ -6,11 +6,15 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" +#include "base/path_service.h" #include "base/run_loop.h" #include "base/test/bind_test_util.h" #include "base/test/task_environment.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h" +#include "chrome/common/chrome_paths.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace safe_browsing { @@ -249,4 +253,37 @@ EXPECT_EQ(sync_data.hash, async_data.hash); } +TEST(FileSourceRequestTest, DetectsEncryption) { + content::BrowserTaskEnvironment browser_task_environment; + content::InProcessUtilityThreadHelper in_process_utility_thread_helper; + + base::FilePath test_zip; + EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_zip)); + test_zip = test_zip.AppendASCII("safe_browsing") + .AppendASCII("download_protection") + .AppendASCII("encrypted.zip"); + + FileSourceRequest request(test_zip, base::DoNothing()); + + BinaryUploadService::Result out_result; + BinaryUploadService::Request::Data out_data; + + base::RunLoop run_loop; + request.GetRequestData(base::BindLambdaForTesting( + [&run_loop, &out_result, &out_data]( + BinaryUploadService::Result result, + const BinaryUploadService::Request::Data& data) { + out_result = result; + out_data = data; + run_loop.Quit(); + })); + run_loop.Run(); + + EXPECT_EQ(out_result, BinaryUploadService::Result::FILE_ENCRYPTED); + // sha256sum chrome/test/data/safe_browsing/download_protection/encrypted.zip + // | tr "[:lower:]" "[:upper:]" + EXPECT_EQ(out_data.hash, + "701FCEA8B2112FFAB257A8A8DFD3382ABCF047689AB028D42903E3B3AA488D9A"); +} + } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc index 3c381e7..e32785d 100644 --- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc +++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
@@ -27,7 +27,6 @@ #include "chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h" #include "chrome/browser/safe_browsing/download_protection/deep_scanning_request.h" #include "chrome/browser/safe_browsing/download_protection/download_feedback_service.h" -#include "chrome/browser/safe_browsing/download_protection/download_item_request.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" #include "chrome/common/safe_browsing/download_type_util.h"
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc index 3f134f54..b049bfce 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc
@@ -10,10 +10,10 @@ #include "base/strings/string_number_conversions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h" +#include "chrome/browser/safe_browsing//cloud_content_scanning/file_source_request.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h" #include "chrome/browser/safe_browsing/dm_token_utils.h" -#include "chrome/browser/safe_browsing/download_protection/download_item_request.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" #include "chrome/browser/ui/browser.h" @@ -175,11 +175,9 @@ // Indicate we're now scanning the file. callback_.Run(DownloadCheckResult::ASYNC_SCANNING); - auto request = std::make_unique<DownloadItemRequest>( - item_, /*read_immediately=*/true, - base::BindOnce(&DeepScanningRequest::OnScanComplete, - weak_ptr_factory_.GetWeakPtr())); - request->set_filename(item_->GetTargetFilePath().BaseName().AsUTF8Unsafe()); + auto request = std::make_unique<FileSourceRequest>( + item_->GetFullPath(), base::BindOnce(&DeepScanningRequest::OnScanComplete, + weak_ptr_factory_.GetWeakPtr())); std::string raw_digest_sha256 = item_->GetHash(); request->set_digest(
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request.cc b/chrome/browser/safe_browsing/download_protection/download_item_request.cc deleted file mode 100644 index 8e3b861..0000000 --- a/chrome/browser/safe_browsing/download_protection/download_item_request.cc +++ /dev/null
@@ -1,200 +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/safe_browsing/download_protection/download_item_request.h" - -#include "base/files/file_path.h" -#include "base/task/post_task.h" -#include "base/task/task_traits.h" -#include "base/task/thread_pool.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/file_util_service.h" -#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h" -#include "chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h" -#include "chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.h" -#include "components/download/public/common/download_item.h" -#include "components/prefs/pref_service.h" -#include "components/safe_browsing/core/common/safe_browsing_prefs.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" - -namespace safe_browsing { - -namespace { - -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(); - if (static_cast<size_t>(file_size) > BinaryUploadService::kMaxUploadSizeBytes) - return ""; - - std::string contents; - contents.resize(file_size); - - int64_t bytes_read = 0; - while (bytes_read < file_size) { - int64_t bytes_currently_read = - file.ReadAtCurrentPos(&contents[bytes_read], file_size - bytes_read); - if (bytes_currently_read == -1) - return ""; - - bytes_read += bytes_currently_read; - } - - return contents; -} - -int GetUnsupportedFiletypesPrefValue() { - return g_browser_process->local_state()->GetInteger( - prefs::kBlockUnsupportedFiletypes); -} - -} // namespace - -DownloadItemRequest::DownloadItemRequest(download::DownloadItem* item, - bool read_immediately, - BinaryUploadService::Callback callback) - : Request(std::move(callback)), item_(item), weakptr_factory_(this) { - if (read_immediately) - ReadFile(); - - item_->AddObserver(this); -} - -DownloadItemRequest::~DownloadItemRequest() { - if (item_ != nullptr) - item_->RemoveObserver(this); -} - -void DownloadItemRequest::GetRequestData(DataCallback callback) { - if (item_ == nullptr) { - std::move(callback).Run(BinaryUploadService::Result::UNKNOWN, Data()); - return; - } - - if (item_ && static_cast<size_t>(item_->GetTotalBytes()) > - BinaryUploadService::kMaxUploadSizeBytes) { - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), - BinaryUploadService::Result::FILE_TOO_LARGE, Data())); - return; - } - - bool malware = deep_scanning_request().has_malware_scan_request(); - bool dlp = deep_scanning_request().has_dlp_scan_request(); - if (item_ && (malware || dlp) && - !FileTypeSupported(malware, dlp, item_->GetTargetFilePath())) { - bool block_file = false; - switch (GetUnsupportedFiletypesPrefValue()) { - case BLOCK_UNSUPPORTED_FILETYPES_NONE: - case BLOCK_UNSUPPORTED_FILETYPES_UPLOADS: - block_file = false; - break; - case BLOCK_UNSUPPORTED_FILETYPES_DOWNLOADS: - case BLOCK_UNSUPPORTED_FILETYPES_UPLOADS_AND_DOWNLOADS: - block_file = true; - } - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), - block_file - ? BinaryUploadService::Result::UNSUPPORTED_FILE_TYPE - : BinaryUploadService::Result::SUCCESS, - Data())); - return; - } - - if (is_data_valid_) { - RunPendingGetFileContentsCallback(std::move(callback)); - return; - } - - pending_callbacks_.push_back(std::move(callback)); -} - -void DownloadItemRequest::RunPendingGetFileContentsCallback( - DataCallback callback) { - if (is_data_encrypted_) { - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), - BinaryUploadService::Result::FILE_ENCRYPTED, Data())); - return; - } - - if (is_data_valid_) { - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), - BinaryUploadService::Result::SUCCESS, data_)); - return; - } -} - -void DownloadItemRequest::OnDownloadUpdated(download::DownloadItem* download) { - if (!is_data_valid_ && download == item_ && - item_->GetFullPath() == item_->GetTargetFilePath()) - ReadFile(); -} - -void DownloadItemRequest::OnDownloadDestroyed( - download::DownloadItem* download) { - if (download == item_) - item_ = nullptr; -} - -void DownloadItemRequest::ReadFile() { - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()}, - base::BindOnce(&GetFileContentsBlocking, item_->GetFullPath()), - base::BindOnce(&DownloadItemRequest::OnGotFileContents, - weakptr_factory_.GetWeakPtr())); -} - -void DownloadItemRequest::OnGotFileContents(std::string contents) { - data_.contents = std::move(contents); - base::FilePath current_path; - base::FilePath::StringType extension; - if (item_) { - current_path = item_->GetFullPath(); - extension = item_->GetTargetFilePath().Extension(); - } - - if (extension == FILE_PATH_LITERAL(".zip")) { - auto analyzer = base::MakeRefCounted<SandboxedZipAnalyzer>( - current_path, - base::BindOnce(&DownloadItemRequest::OnCheckedForEncryption, - weakptr_factory_.GetWeakPtr()), - LaunchFileUtilService()); - analyzer->Start(); - } else if (extension == FILE_PATH_LITERAL(".rar")) { - auto analyzer = base::MakeRefCounted<SandboxedRarAnalyzer>( - current_path, - base::BindOnce(&DownloadItemRequest::OnCheckedForEncryption, - weakptr_factory_.GetWeakPtr()), - LaunchFileUtilService()); - analyzer->Start(); - } else { - OnCheckedForEncryption(ArchiveAnalyzerResults()); - } -} - -void DownloadItemRequest::OnCheckedForEncryption( - const ArchiveAnalyzerResults& results) { - is_data_valid_ = true; - is_data_encrypted_ = std::any_of( - results.archived_binary.begin(), results.archived_binary.end(), - [](const auto& binary) { return binary.is_encrypted(); }); - - for (auto& callback : pending_callbacks_) { - RunPendingGetFileContentsCallback(std::move(callback)); - } - - pending_callbacks_.clear(); -} - -} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request.h b/chrome/browser/safe_browsing/download_protection/download_item_request.h deleted file mode 100644 index 82ee386d..0000000 --- a/chrome/browser/safe_browsing/download_protection/download_item_request.h +++ /dev/null
@@ -1,78 +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_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_ITEM_REQUEST_H_ -#define CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_ITEM_REQUEST_H_ - -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h" -#include "chrome/common/safe_browsing/archive_analyzer_results.h" -#include "components/download/public/common/download_item.h" - -namespace safe_browsing { - -// This class implements the BinaryUploadService::Request interface for a -// particular DownloadItem. It is neither moveable nor copyable. -class DownloadItemRequest : public BinaryUploadService::Request, - download::DownloadItem::Observer { - public: - // Create a DownloadItemRequest for the given |item|. If |read_immediately| is - // true, try to read the file contents right away. Otherwise, wait until the - // file has been renamed to its final path. If the caller expects |item| to be - // renamed imminently, it's recommended to set |read_immediately| to false, - // to avoid race conditions while reading the file. - DownloadItemRequest(download::DownloadItem* item, - bool read_immediately, - BinaryUploadService::Callback callback); - ~DownloadItemRequest() override; - - DownloadItemRequest(const DownloadItemRequest&) = delete; - DownloadItemRequest& operator=(const DownloadItemRequest&) = delete; - DownloadItemRequest(DownloadItemRequest&&) = delete; - DownloadItemRequest& operator=(DownloadItemRequest&&) = delete; - - // BinaryUploadService::Request implementation. - void GetRequestData(DataCallback callback) override; - - // download::DownloadItem::Observer implementation. - void OnDownloadDestroyed(download::DownloadItem* download) override; - void OnDownloadUpdated(download::DownloadItem* download) override; - - private: - void ReadFile(); - - void OnGotFileContents(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 one of those - // callbacks. The callbacks are all run asynchronously, as they may delete - // |this|. - void RunPendingGetFileContentsCallback(DataCallback callback); - - // Called when the file contents have finished being checked for encryption. - void OnCheckedForEncryption(const ArchiveAnalyzerResults& results); - - // Pointer the download item for upload. This must be accessed only the UI - // thread. Unowned. - download::DownloadItem* item_; - - // The file's data. - Data data_; - - // Is the |data_| member valid? It becomes valid once the file has been - // read successfully. - bool is_data_valid_ = false; - - // Is the |data_| member encrypted? - bool is_data_encrypted_ = false; - - // All pending callbacks to GetFileContents before the download item is ready. - std::vector<DataCallback> pending_callbacks_; - - base::WeakPtrFactory<DownloadItemRequest> weakptr_factory_; -}; -} // namespace safe_browsing - -#endif // CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_DOWNLOAD_ITEM_REQUEST_H_
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 deleted file mode 100644 index 9055108..0000000 --- a/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc +++ /dev/null
@@ -1,92 +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/safe_browsing/download_protection/download_item_request.h" - -#include "base/bind_helpers.h" -#include "base/callback_forward.h" -#include "base/files/scoped_temp_dir.h" -#include "base/run_loop.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::TestWithParam<bool> { - public: - DownloadItemRequestTest() - : item_(), - request_(&item_, /*read_immediately=*/false, 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_ = large_contents() ? std::string(51 * 1024 * 1024, 'a') - : "download contents"; - file.Write(0, download_contents_.c_str(), download_contents_.size()); - file.Close(); - - EXPECT_CALL(item_, GetTotalBytes()) - .WillRepeatedly(Return(download_contents_.size())); - EXPECT_CALL(item_, GetTargetFilePath()) - .WillRepeatedly(ReturnRef(download_path_)); - EXPECT_CALL(item_, GetFullPath()).WillRepeatedly(ReturnRef(download_path_)); - } - - bool large_contents() const { return GetParam(); } - - protected: - content::BrowserTaskEnvironment task_environment_; - download::MockDownloadItem item_; - DownloadItemRequest request_; - base::ScopedTempDir temp_dir_; - base::FilePath download_path_; - base::FilePath download_temporary_path_; - std::string download_contents_; -}; - -TEST_P(DownloadItemRequestTest, GetsContentsWaitsUntilRename) { - ON_CALL(item_, GetFullPath()) - .WillByDefault(ReturnRef(download_temporary_path_)); - - std::string download_contents = ""; - request_.GetRequestData(base::BindOnce( - [](std::string* target_contents, BinaryUploadService::Result result, - const BinaryUploadService::Request::Data& data) { - *target_contents = data.contents; - }, - &download_contents)); - content::RunAllTasksUntilIdle(); - EXPECT_EQ(download_contents, ""); - - ON_CALL(item_, GetFullPath()).WillByDefault(ReturnRef(download_path_)); - item_.NotifyObserversDownloadUpdated(); - - content::RunAllTasksUntilIdle(); - - // The contents should not be read if they are too large. - if (large_contents()) - EXPECT_EQ(download_contents, ""); - else - EXPECT_EQ(download_contents, "download contents"); -} - -INSTANTIATE_TEST_SUITE_P(DownloadItemRequestTest, - DownloadItemRequestTest, - testing::Bool()); - -} // namespace safe_browsing
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc index f131e22..3d942d3c 100644 --- a/chrome/browser/shell_integration_win.cc +++ b/chrome/browser/shell_integration_win.cc
@@ -735,20 +735,6 @@ // This needs to happen (e.g. so that the appid is fixed and the // run-time Chrome icon is merged with the taskbar shortcut), but it is not an // urgent task. - base::FilePath taskbar_path; - if (!base::PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_path)) { - NOTREACHED(); - return; - } - - // Migrate any pinned shortcuts in ImplicitApps sub-directories. - base::FilePath implicit_apps_path; - if (!base::PathService::Get(base::DIR_IMPLICIT_APP_SHORTCUTS, - &implicit_apps_path)) { - NOTREACHED(); - return; - } - // MigrateTaskbarPinsCallback just calls MigrateShortcutsInPathInternal // several times with different parameters. Each call may or may not load // DLL's. Since the callback may take the loader lock several times, and this @@ -761,10 +747,16 @@ base::ThreadPool::CreateCOMSTATaskRunner( {base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::ThreadPolicy::MUST_USE_FOREGROUND}) - ->PostTaskAndReply(FROM_HERE, - base::BindOnce(&MigrateTaskbarPinsCallback, - taskbar_path, implicit_apps_path), - std::move(completion_callback)); + ->PostTaskAndReply( + FROM_HERE, base::BindOnce([]() { + base::FilePath taskbar_path; + base::FilePath implicit_apps_path; + base::PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_path); + base::PathService::Get(base::DIR_IMPLICIT_APP_SHORTCUTS, + &implicit_apps_path); + MigrateTaskbarPinsCallback(taskbar_path, implicit_apps_path); + }), + std::move(completion_callback)); } void MigrateTaskbarPinsCallback(const base::FilePath& taskbar_path, @@ -775,8 +767,12 @@ return; base::FilePath chrome_proxy_path(web_app::GetChromeProxyPath()); - MigrateChromeAndChromeProxyShortcuts(chrome_exe, chrome_proxy_path, - taskbar_path); + if (!taskbar_path.empty()) { + MigrateChromeAndChromeProxyShortcuts(chrome_exe, chrome_proxy_path, + taskbar_path); + } + if (implicit_apps_path.empty()) + return; base::FileEnumerator directory_enum(implicit_apps_path, /*recursive=*/false, base::FileEnumerator::DIRECTORIES); for (base::FilePath implicit_app_sub_directory = directory_enum.Next();
diff --git a/chrome/browser/sync/test/integration/password_manager_sync_test.cc b/chrome/browser/sync/test/integration/password_manager_sync_test.cc new file mode 100644 index 0000000..f836f9b9 --- /dev/null +++ b/chrome/browser/sync/test/integration/password_manager_sync_test.cc
@@ -0,0 +1,256 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <string> + +#include "base/callback_list.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "build/build_config.h" +#include "chrome/browser/password_manager/account_storage/account_password_store_factory.h" +#include "chrome/browser/password_manager/password_manager_test_base.h" +#include "chrome/browser/password_manager/password_store_factory.h" +#include "chrome/browser/sync/test/integration/passwords_helper.h" +#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/integration/secondary_account_helper.h" +#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" +#include "chrome/browser/sync/test/integration/sync_test.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/password_manager/core/browser/password_manager_test_utils.h" +#include "components/password_manager/core/browser/password_manager_util.h" +#include "components/password_manager/core/browser/test_password_store.h" +#include "components/password_manager/core/common/password_manager_features.h" +#include "components/sync/driver/profile_sync_service.h" +#include "components/sync/driver/sync_driver_switches.h" +#include "net/dns/mock_host_resolver.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +using testing::ElementsAre; + +MATCHER_P2(MatchesLogin, username, password, "") { + return arg->username_value == base::UTF8ToUTF16(username) && + arg->password_value == base::UTF8ToUTF16(password); +} + +// Note: This helper applies to ChromeOS too, but is currently unused there. So +// define it out to prevent a compile error due to the unused function. +#if !defined(OS_CHROMEOS) +void GetNewTab(Browser* browser, content::WebContents** web_contents) { + PasswordManagerBrowserTestBase::GetNewTab(browser, web_contents); +} +#endif // !defined(OS_CHROMEOS) + +class PasswordSyncActiveChecker : public SingleClientStatusChangeChecker { + public: + explicit PasswordSyncActiveChecker(syncer::ProfileSyncService* service) + : SingleClientStatusChangeChecker(service) {} + ~PasswordSyncActiveChecker() override = default; + + // SingleClientStatusChangeChecker. + bool IsExitConditionSatisfied(std::ostream* os) override { + return service()->GetActiveDataTypes().Has(syncer::PASSWORDS); + } +}; + +// This test fixture is similar to SingleClientPasswordsSyncTest, but it also +// sets up all the necessary test hooks etc for PasswordManager code (like +// PasswordManagerBrowserTestBase), to allow for integration tests covering +// both Sync and the PasswordManager. +class PasswordManagerSyncTest : public SyncTest { + public: + PasswordManagerSyncTest() : SyncTest(SINGLE_CLIENT) { + feature_list_.InitWithFeatures( + /*enabled_features=*/{switches::kSyncUSSPasswords, + password_manager::features:: + kEnablePasswordsAccountStorage}, + /*disabled_features=*/{}); + } + ~PasswordManagerSyncTest() override = default; + + void SetUpInProcessBrowserTestFixture() override { + SyncTest::SetUpInProcessBrowserTestFixture(); + + test_signin_client_factory_ = + secondary_account_helper::SetUpSigninClient(&test_url_loader_factory_); + + will_create_browser_context_services_subscription_ = + BrowserContextDependencyManager::GetInstance() + ->RegisterWillCreateBrowserContextServicesCallbackForTesting( + base::BindRepeating(&PasswordManagerSyncTest:: + OnWillCreateBrowserContextServices)); + } + + static void OnWillCreateBrowserContextServices( + content::BrowserContext* context) { + // Use TestPasswordStore to remove a possible race. Normally the + // PasswordStore does its database manipulation on a background thread, + // which creates a possible race during navigation. Specifically the + // PasswordManager will ignore any forms in a page if the load from the + // PasswordStore has not completed. + // TODO(crbug.com/1058339): Investigate whether these test doubles are + // really required, or whether we can use the real stores and add some + // waiting logic. + PasswordStoreFactory::GetInstance()->SetTestingFactory( + context, + base::BindRepeating(&password_manager::BuildPasswordStoreWithArgs< + content::BrowserContext, + password_manager::TestPasswordStore, bool>, + /*is_account_store=*/false)); + AccountPasswordStoreFactory::GetInstance()->SetTestingFactory( + context, + base::BindRepeating(&password_manager::BuildPasswordStoreWithArgs< + content::BrowserContext, + password_manager::TestPasswordStore, bool>, + /*is_account_store=*/true)); + } + + void SetUpOnMainThread() override { + SyncTest::SetUpOnMainThread(); + + ASSERT_TRUE(embedded_test_server()->Start()); + host_resolver()->AddRule("*", "127.0.0.1"); + } + + void TearDownOnMainThread() override { + ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); + SyncTest::TearDownOnMainThread(); + } + + // Synchronously reads all credentials from the profile password store and + // returns them. + std::vector<std::unique_ptr<autofill::PasswordForm>> + GetAllLoginsFromProfilePasswordStore() { + scoped_refptr<password_manager::PasswordStore> password_store = + passwords_helper::GetPasswordStore(0); + PasswordStoreResultsObserver syncer; + password_store->GetAllLoginsWithAffiliationAndBrandingInformation(&syncer); + return syncer.WaitForResults(); + } + + // Synchronously reads all credentials from the account password store and + // returns them. + std::vector<std::unique_ptr<autofill::PasswordForm>> + GetAllLoginsFromAccountPasswordStore() { + scoped_refptr<password_manager::PasswordStore> password_store = + passwords_helper::GetAccountPasswordStore(0); + PasswordStoreResultsObserver syncer; + password_store->GetAllLoginsWithAffiliationAndBrandingInformation(&syncer); + return syncer.WaitForResults(); + } + + void NavigateToFile(content::WebContents* web_contents, + const std::string& path) { + ASSERT_EQ(web_contents, + GetBrowser(0)->tab_strip_model()->GetActiveWebContents()); + NavigationObserver observer(web_contents); + GURL url = embedded_test_server()->GetURL(path); + ui_test_utils::NavigateToURL(GetBrowser(0), url); + observer.Wait(); + } + + private: + base::test::ScopedFeatureList feature_list_; + + secondary_account_helper::ScopedSigninClientFactory + test_signin_client_factory_; + + std::unique_ptr< + base::CallbackList<void(content::BrowserContext*)>::Subscription> + will_create_browser_context_services_subscription_; +}; + +#if !defined(OS_CHROMEOS) +IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTest, ChooseDestinationStore) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + content::WebContents* web_contents = nullptr; + GetNewTab(GetBrowser(0), &web_contents); + + // Setup Sync for a secondary account (i.e. in transport mode). + secondary_account_helper::SignInSecondaryAccount( + GetProfile(0), &test_url_loader_factory_, "user@email.com"); + ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive()); + ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled()); + + // Let the user opt in to the passwords account storage, and wait for it to + // become active. + password_manager_util::SetAccountStorageOptIn(GetProfile(0)->GetPrefs(), + GetSyncService(0), true); + PasswordSyncActiveChecker(GetSyncService(0)).Wait(); + ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PASSWORDS)); + + // Part 1: Save a password; it should go into the account store by default. + { + // Navigate to a page with a password form. + NavigateToFile(web_contents, "/password/password_form.html"); + + // Fill out and submit the password form. + NavigationObserver observer(web_contents); + std::string fill_and_submit = + "document.getElementById('username_field').value = 'accountuser';" + "document.getElementById('password_field').value = 'accountpass';" + "document.getElementById('input_submit_button').click()"; + ASSERT_TRUE(content::ExecJs(web_contents, fill_and_submit)); + observer.Wait(); + + // Save the password and check the store. + BubbleObserver bubble_observer(web_contents); + ASSERT_TRUE(bubble_observer.IsSavePromptShownAutomatically()); + bubble_observer.AcceptSavePrompt(); + + std::vector<std::unique_ptr<autofill::PasswordForm>> account_credentials = + GetAllLoginsFromAccountPasswordStore(); + EXPECT_THAT(account_credentials, + ElementsAre(MatchesLogin("accountuser", "accountpass"))); + } + + // Part 2: Mimic the user choosing to save locally; now a newly saved password + // should end up in the profile store. + password_manager_util::SetDefaultPasswordStore( + GetProfile(0)->GetPrefs(), GetSyncService(0), + autofill::PasswordForm::Store::kProfileStore); + { + // Navigate to a page with a password form. + // TODO(crbug.com/1058339): If we use the same URL as in part 1 here, then + // the test fails because the *account* data gets filled and submitted + // again. This is because the password manager is "smart" and prefers + // user-typed values (including autofilled-on-pageload ones) over + // script-provided values, see + // https://cs.chromium.org/chromium/src/components/autofill/content/renderer/form_autofill_util.cc?rcl=e38f0c99fe45ef81bd09d97f235c3dee64e2bd9f&l=1749 + // and + // https://cs.chromium.org/chromium/src/components/autofill/content/renderer/password_autofill_agent.cc?rcl=63830d3f4b7f5fceec9609d83cf909d0cad04bb2&l=1855 + // Some PasswordManager browser tests work around this by disabling + // autofill on pageload, see PasswordManagerBrowserTestWithAutofillDisabled. + // NavigateToFile(web_contents, "/password/password_form.html"); + NavigateToFile(web_contents, "/password/simple_password.html"); + + // Fill out and submit the password form. + NavigationObserver observer(web_contents); + std::string fill_and_submit = + "document.getElementById('username_field').value = 'localuser';" + "document.getElementById('password_field').value = 'localpass';" + "document.getElementById('input_submit_button').click()"; + ASSERT_TRUE(content::ExecJs(web_contents, fill_and_submit)); + observer.Wait(); + + // Save the password and check the store. + BubbleObserver bubble_observer(web_contents); + ASSERT_TRUE(bubble_observer.IsSavePromptShownAutomatically()); + bubble_observer.AcceptSavePrompt(); + + std::vector<std::unique_ptr<autofill::PasswordForm>> profile_credentials = + GetAllLoginsFromProfilePasswordStore(); + EXPECT_THAT(profile_credentials, + ElementsAre(MatchesLogin("localuser", "localpass"))); + } +} +#endif // !defined(OS_CHROMEOS) + +} // namespace
diff --git a/chrome/browser/ui/ash/homescreen_interactive_uitest.cc b/chrome/browser/ui/ash/homescreen_interactive_uitest.cc index 3044e771..dab02f9 100644 --- a/chrome/browser/ui/ash/homescreen_interactive_uitest.cc +++ b/chrome/browser/ui/ash/homescreen_interactive_uitest.cc
@@ -52,7 +52,8 @@ } }; -IN_PROC_BROWSER_TEST_F(HomescreenTest, ShowHideLauncher) { +// Disabled: crbug.com/1060648 +IN_PROC_BROWSER_TEST_F(HomescreenTest, DISABLED_ShowHideLauncher) { BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow();
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_button.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_button.cc index 2a40adf..50ad644 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_button.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_button.cc
@@ -47,6 +47,13 @@ return extensions_container_->GetToolbarActionSize(); } +gfx::Size ExtensionsToolbarButton::GetMinimumSize() const { + const int icon_size = GetIconSize(); + gfx::Size min_size(icon_size, icon_size); + min_size.SetToMin(GetPreferredSize()); + return min_size; +} + void ExtensionsToolbarButton::OnBoundsChanged( const gfx::Rect& previous_bounds) { // Because this button is in a container and doesn't necessarily take up the
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_button.h b/chrome/browser/ui/views/extensions/extensions_toolbar_button.h index b2d33a7f..73263d55 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_button.h +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_button.h
@@ -27,6 +27,7 @@ private: // ToolbarButton: gfx::Size CalculatePreferredSize() const override; + gfx::Size GetMinimumSize() const override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override; const char* GetClassName() const override;
diff --git a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc index 29b2eec..101fc03 100644 --- a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc +++ b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc
@@ -282,7 +282,8 @@ else combobox->SetSelectedRow(1); - // TODO(crbug.com/1044038): SetAccessibleName of the combobox. + // TODO(crbug.com/1044038): Use an internationalized string instead. + combobox->SetAccessibleName(base::ASCIIToUTF16("Destination")); return combobox; }
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc index 2f9147e..5e9036d 100644 --- a/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -336,6 +336,11 @@ html_source->AddResourcePath( "images/password_check_neutral_dark.svg", IDR_SETTINGS_IMAGES_PASSWORD_CHECK_NEUTRAL_DARK_SVG); + html_source->AddResourcePath("images/password_check_positive.svg", + IDR_SETTINGS_IMAGES_PASSWORD_CHECK_POSITIVE_SVG); + html_source->AddResourcePath( + "images/password_check_positive_dark.svg", + IDR_SETTINGS_IMAGES_PASSWORD_CHECK_POSITIVE_DARK_SVG); // Only used in Polymer 3, see https://crbug.com/1026426. html_source->AddResourcePath("settings.js", IDR_SETTINGS_SETTINGS_ROLLUP_JS);
diff --git a/chrome/credential_provider/eventlog/BUILD.gn b/chrome/credential_provider/eventlog/BUILD.gn index 6ddc4355..a0e01ac 100644 --- a/chrome/credential_provider/eventlog/BUILD.gn +++ b/chrome/credential_provider/eventlog/BUILD.gn
@@ -24,7 +24,7 @@ "gcp_eventlog_provider.cc", ] - if (!is_asan && !use_clang_coverage) { + if (!is_asan && !use_clang_profiling) { no_default_deps = true ldflags = [ "/NOENTRY" ] }
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc index 502fc4f..6a53ac6 100644 --- a/chrome/installer/util/shell_util.cc +++ b/chrome/installer/util/shell_util.cc
@@ -1603,8 +1603,8 @@ folder_to_append = InstallUtil::GetChromeAppsShortcutDirName(); break; case SHORTCUT_LOCATION_TASKBAR_PINS: - dir_key = base::DIR_TASKBAR_PINS; - break; + // This directory isn't guaranteed to exist. + return base::PathService::Get(base::DIR_TASKBAR_PINS, path); case SHORTCUT_LOCATION_APP_SHORTCUTS: // TODO(huangs): Move GetAppShortcutsFolder() logic into base_paths_win. return GetAppShortcutsFolder(level, path);
diff --git a/chrome/services/util_win/util_win_impl.cc b/chrome/services/util_win/util_win_impl.cc index 9ff113e..32f1035 100644 --- a/chrome/services/util_win/util_win_impl.cc +++ b/chrome/services/util_win/util_win_impl.cc
@@ -188,21 +188,24 @@ bool IsPinnedToTaskbarHelper::GetResult() { base::FilePath current_exe; - base::PathService::Get(base::FILE_EXE, ¤t_exe); + if (!base::PathService::Get(base::FILE_EXE, ¤t_exe)) + return false; InstallUtil::ProgramCompare current_exe_compare(current_exe); // Look into the "Quick Launch\User Pinned\TaskBar" folder. base::FilePath taskbar_pins_dir; - base::PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_pins_dir); - if (DirectoryContainsPinnedShortcutForProgram(taskbar_pins_dir, + if (base::PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_pins_dir) && + DirectoryContainsPinnedShortcutForProgram(taskbar_pins_dir, current_exe_compare)) { return true; } // Check all folders in ImplicitAppShortcuts. base::FilePath implicit_app_shortcuts_dir; - base::PathService::Get(base::DIR_IMPLICIT_APP_SHORTCUTS, - &implicit_app_shortcuts_dir); + if (!base::PathService::Get(base::DIR_IMPLICIT_APP_SHORTCUTS, + &implicit_app_shortcuts_dir)) { + return false; + } base::FileEnumerator directory_enum(implicit_app_shortcuts_dir, false, base::FileEnumerator::DIRECTORIES); for (base::FilePath directory = directory_enum.Next(); !directory.empty();
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 58eb1a27..2763ff2 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -4968,7 +4968,6 @@ "../browser/safe_browsing/download_protection/deep_scanning_request_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/path_sanitizer_unittest.cc", @@ -6283,6 +6282,7 @@ "../browser/sync/test/integration/enable_disable_test.cc", "../browser/sync/test/integration/local_sync_test.cc", "../browser/sync/test/integration/migration_test.cc", + "../browser/sync/test/integration/password_manager_sync_test.cc", "../browser/sync/test/integration/single_client_app_settings_sync_test.cc", "../browser/sync/test/integration/single_client_apps_sync_test.cc", "../browser/sync/test/integration/single_client_autofill_profile_sync_test.cc", @@ -6334,6 +6334,7 @@ ] data = [ + "//chrome/test/data/password/", "//chrome/test/data/sync/", "//net/tools/testserver/", "//third_party/pywebsocket3/src/mod_pywebsocket/",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/WebApkInfoBuilder.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/WebApkInfoBuilder.java index e60d038..dc70df9 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/WebApkInfoBuilder.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/WebApkInfoBuilder.java
@@ -50,7 +50,7 @@ * Builds {@link WebApkInfo} object using options that have been set. */ public WebApkInfo build() { - return WebApkInfo.create(mUrl, mScope, null, null, null, null, null, mDisplayMode, + return WebApkInfo.create(mUrl, mScope, null, null, null, null, mDisplayMode, ScreenOrientationValues.DEFAULT, ShortcutSource.UNKNOWN, ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING, ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING, Color.WHITE,
diff --git a/chrome/test/data/extensions/test_file_with_trusted_types.html b/chrome/test/data/extensions/test_file_with_trusted_types.html index 85485a05..e5e85c4 100644 --- a/chrome/test/data/extensions/test_file_with_trusted_types.html +++ b/chrome/test/data/extensions/test_file_with_trusted_types.html
@@ -1,7 +1,7 @@ <!doctype html> <html> <head> - <meta http-equiv="Content-Security-Policy" content="trusted-types *"> + <meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'"> <title>Define a restrictive CSP trusted-types directive.</title> </head> <body>
diff --git a/chrome/test/data/webui/settings/password_check_test.js b/chrome/test/data/webui/settings/password_check_test.js index 747411a9..75b5169 100644 --- a/chrome/test/data/webui/settings/password_check_test.js +++ b/chrome/test/data/webui/settings/password_check_test.js
@@ -39,7 +39,8 @@ } function isElementVisible(element) { - return !!element && !element.hidden && element.style.display != 'none'; + return !!element && !element.hidden && element.style.display != 'none' && + element.offsetParent !== null; // Considers parents hiding |element|. } /** @@ -642,6 +643,112 @@ section.$.controlPasswordCheckButton.innerText); }); }); + + // Test that the banner is in a state that shows the positive confirmation + // after a leak check finished. + test('testShowsPositiveBannerWhenIdle', function() { + const data = passwordManager.data; + assertEquals(PasswordCheckState.IDLE, data.checkStatus.state); + assertEquals(0, data.leakedCredentials.length); + + const checkPasswordSection = createCheckPasswordSection(); + return passwordManager.whenCalled('getPasswordCheckStatus').then(() => { + Polymer.dom.flush(); + assertTrue(isElementVisible(checkPasswordSection.$$('#bannerImage'))); + expectEquals( + 'chrome://settings/images/password_check_positive.svg', + checkPasswordSection.$$('#bannerImage').src); + }); + }); + + // Test that the banner is in a state that shows that the leak check is + // in progress but hasn't found anything yet. + test('testShowsNeutralBannerWhenRunning', function() { + const data = passwordManager.data; + assertEquals(0, data.leakedCredentials.length); + data.checkStatus = autofill_test_util.makePasswordCheckStatus( + /*state=*/ PasswordCheckState.RUNNING, /*checked=*/ 1, + /*remaining=*/ 5); + + const checkPasswordSection = createCheckPasswordSection(); + return passwordManager.whenCalled('getPasswordCheckStatus').then(() => { + Polymer.dom.flush(); + assertTrue(isElementVisible(checkPasswordSection.$$('#bannerImage'))); + expectEquals( + 'chrome://settings/images/password_check_neutral.svg', + checkPasswordSection.$$('#bannerImage').src); + }); + }); + + // Test that the banner is in a state that shows that the leak check is + // in progress but hasn't found anything yet. + test('testShowsNeutralBannerWhenCanceled', function() { + const data = passwordManager.data; + assertEquals(0, data.leakedCredentials.length); + data.checkStatus = autofill_test_util.makePasswordCheckStatus( + /*state=*/ PasswordCheckState.CANCELED); + + const checkPasswordSection = createCheckPasswordSection(); + return passwordManager.whenCalled('getPasswordCheckStatus').then(() => { + Polymer.dom.flush(); + assertTrue(isElementVisible(checkPasswordSection.$$('#bannerImage'))); + expectEquals( + 'chrome://settings/images/password_check_neutral.svg', + checkPasswordSection.$$('#bannerImage').src); + }); + }); + + // Test that the banner isn't visible as soon as the first leak is detected. + test('testLeaksHideBannerWhenRunning', function() { + const data = passwordManager.data; + data.checkStatus = autofill_test_util.makePasswordCheckStatus( + /*state=*/ PasswordCheckState.RUNNING, /*checked=*/ 1, + /*remaining=*/ 5); + data.leakedCredentials = [ + autofill_test_util.makeCompromisedCredential( + 'one.com', 'test4', 'LEAKED'), + ]; + + const checkPasswordSection = createCheckPasswordSection(); + return passwordManager.whenCalled('getPasswordCheckStatus').then(() => { + Polymer.dom.flush(); + expectFalse(isElementVisible(checkPasswordSection.$$('#bannerImage'))); + }); + }); + + // Test that the banner isn't visible if a leak is detected after a check. + test('testLeaksHideBannerWhenIdle', function() { + const data = passwordManager.data; + data.checkStatus = autofill_test_util.makePasswordCheckStatus( + /*state=*/ PasswordCheckState.IDLE); + data.leakedCredentials = [ + autofill_test_util.makeCompromisedCredential( + 'one.com', 'test4', 'LEAKED'), + ]; + + const checkPasswordSection = createCheckPasswordSection(); + return passwordManager.whenCalled('getPasswordCheckStatus').then(() => { + Polymer.dom.flush(); + expectFalse(isElementVisible(checkPasswordSection.$$('#bannerImage'))); + }); + }); + + // Test that the banner isn't visible if a leak is detected after canceling. + test('testLeaksHideBannerWhenCanceled', function() { + const data = passwordManager.data; + data.checkStatus = autofill_test_util.makePasswordCheckStatus( + /*state=*/ PasswordCheckState.CANCELED); + data.leakedCredentials = [ + autofill_test_util.makeCompromisedCredential( + 'one.com', 'test4', 'LEAKED'), + ]; + + const checkPasswordSection = createCheckPasswordSection(); + return passwordManager.whenCalled('getPasswordCheckStatus').then(() => { + Polymer.dom.flush(); + expectFalse(isElementVisible(checkPasswordSection.$$('#bannerImage'))); + }); + }); }); // #cr_define_end });
diff --git a/chromecast/browser/cast_web_view_default.cc b/chromecast/browser/cast_web_view_default.cc index b24749c..4504f3b3 100644 --- a/chromecast/browser/cast_web_view_default.cc +++ b/chromecast/browser/cast_web_view_default.cc
@@ -43,7 +43,6 @@ content::BrowserContext* browser_context, scoped_refptr<content::SiteInstance> site_instance) { content::WebContents::CreateParams create_params(browser_context, nullptr); - create_params.routing_id = MSG_ROUTING_NONE; create_params.site_instance = site_instance; return content::WebContents::Create(create_params); }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index a8b2ca9..cf2af3d 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -12966.0.0 \ No newline at end of file +12968.0.0 \ No newline at end of file
diff --git a/components/autofill_assistant/browser/basic_interactions.cc b/components/autofill_assistant/browser/basic_interactions.cc index 4c8abea5..6b838803f 100644 --- a/components/autofill_assistant/browser/basic_interactions.cc +++ b/components/autofill_assistant/browser/basic_interactions.cc
@@ -4,6 +4,9 @@ #include "components/autofill_assistant/browser/basic_interactions.h" #include "base/bind_helpers.h" +#include "base/i18n/time_formatting.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "components/autofill_assistant/browser/script_executor_delegate.h" #include "components/autofill_assistant/browser/trigger_context.h" #include "components/autofill_assistant/browser/user_model.h" @@ -78,6 +81,74 @@ return true; } +bool ValueToString(UserModel* user_model, + const std::string& result_model_identifier, + const ToStringProto& proto) { + auto value = user_model->GetValue(proto.model_identifier()); + std::string result; + + if (!value.has_value()) { + DVLOG(2) << "Error evaluating " << __func__ << ": " + << proto.model_identifier() << " not found in model"; + return false; + } + if (!AreAllValuesOfSize({*value}, 1)) { + DVLOG(2) << "Error evaluating " << __func__ + << ": expected single value, but got a list instead"; + return false; + } + if (AreAllValuesOfType({*value}, ValueProto::kUserActions)) { + DVLOG(2) << "Error evaluating " << __func__ + << ": does not support stringifying user actions"; + return false; + } + switch (value->kind_case()) { + case ValueProto::kStrings: + result = value->strings().values(0); + break; + case ValueProto::kBooleans: + result = value->booleans().values(0) ? "true" : "false"; + break; + case ValueProto::kInts: + result = base::NumberToString(value->ints().values(0)); + break; + case ValueProto::kUserActions: + NOTREACHED(); + return false; + case ValueProto::kDates: { + if (proto.date_format().date_format().empty()) { + DVLOG(2) << "Error evaluating " << __func__ << ": date_format not set"; + return false; + } + auto date = value->dates().values(0); + base::Time::Exploded exploded_time = {date.year(), + date.month(), + /* day_of_week = */ -1, + date.day(), + /* hour = */ 0, + /* minute = */ 0, + /* second = */ 0, + /* millisecond = */ 0}; + base::Time time; + if (!base::Time::FromLocalExploded(exploded_time, &time)) { + DVLOG(2) << "Error evaluating " << __func__ << ": invalid date " + << *value; + return false; + } + + result = base::UTF16ToUTF8(base::TimeFormatWithPattern( + time, proto.date_format().date_format().c_str())); + break; + } + case ValueProto::KIND_NOT_SET: + DVLOG(2) << "Error evaluating " << __func__ << ": kind not set"; + return false; + } + + user_model->SetValue(result_model_identifier, SimpleValue(result)); + return true; +} + } // namespace base::WeakPtr<BasicInteractions> BasicInteractions::GetWeakPtr() { @@ -129,6 +200,14 @@ } return BooleanNot(delegate_->GetUserModel(), proto.result_model_identifier(), proto.boolean_not()); + case ComputeValueProto::kToString: + if (proto.to_string().model_identifier().empty()) { + DVLOG(2) << "Error computing ComputeValue::ToString: " + "model_identifier not specified"; + return false; + } + return ValueToString(delegate_->GetUserModel(), + proto.result_model_identifier(), proto.to_string()); case ComputeValueProto::KIND_NOT_SET: DVLOG(2) << "Error computing value: kind not set"; return false;
diff --git a/components/autofill_assistant/browser/basic_interactions_unittest.cc b/components/autofill_assistant/browser/basic_interactions_unittest.cc index 51d8423a..f153fd3 100644 --- a/components/autofill_assistant/browser/basic_interactions_unittest.cc +++ b/components/autofill_assistant/browser/basic_interactions_unittest.cc
@@ -4,6 +4,7 @@ #include "components/autofill_assistant/browser/basic_interactions.h" #include "base/test/gmock_callback_support.h" +#include "base/test/icu_test_util.h" #include "base/test/mock_callback.h" #include "components/autofill_assistant/browser/fake_script_executor_delegate.h" #include "components/autofill_assistant/browser/interactions.pb.h" @@ -12,6 +13,16 @@ namespace autofill_assistant { +namespace { +DateProto CreateDateProto(int year, int month, int day) { + DateProto proto; + proto.set_year(year); + proto.set_month(month); + proto.set_day(day); + return proto; +} +} // namespace + class BasicInteractionsTest : public testing::Test { protected: BasicInteractionsTest() { delegate_.SetUserModel(&user_model_); } @@ -127,6 +138,64 @@ EXPECT_FALSE(basic_interactions_.ComputeValue(proto)); } +TEST_F(BasicInteractionsTest, ComputeValueToString) { + ComputeValueProto proto; + proto.mutable_to_string()->set_model_identifier("value"); + user_model_.SetValue("value", SimpleValue(1)); + + // Result model identifier not set. + EXPECT_FALSE(basic_interactions_.ComputeValue(proto)); + + // Integer + proto.set_result_model_identifier("output"); + EXPECT_TRUE(basic_interactions_.ComputeValue(proto)); + EXPECT_EQ(*user_model_.GetValue("output"), SimpleValue(std::string("1"))); + + // Boolean + user_model_.SetValue("value", SimpleValue(true)); + EXPECT_TRUE(basic_interactions_.ComputeValue(proto)); + EXPECT_EQ(*user_model_.GetValue("output"), SimpleValue(std::string("true"))); + + // String + user_model_.SetValue("value", SimpleValue(std::string("test asd"))); + EXPECT_TRUE(basic_interactions_.ComputeValue(proto)); + EXPECT_EQ(*user_model_.GetValue("output"), + SimpleValue(std::string("test asd"))); + + // Date without format fails. + user_model_.SetValue("value", SimpleValue(CreateDateProto(2020, 10, 23))); + EXPECT_FALSE(basic_interactions_.ComputeValue(proto)); + + // Date with format succeeds. + { + base::test::ScopedRestoreICUDefaultLocale locale(std::string("en_US")); + proto.mutable_to_string()->mutable_date_format()->set_date_format( + "EEE, MMM d y"); + EXPECT_TRUE(basic_interactions_.ComputeValue(proto)); + EXPECT_EQ(*user_model_.GetValue("output"), + SimpleValue(std::string("Fri, Oct 23, 2020"))); + } + + // Date in german locale. + { + base::test::ScopedRestoreICUDefaultLocale locale(std::string("de_DE")); + EXPECT_TRUE(basic_interactions_.ComputeValue(proto)); + EXPECT_EQ(*user_model_.GetValue("output"), + SimpleValue(std::string("Fr., 23. Okt. 2020"))); + } + + // Empty value fails. + user_model_.SetValue("value", ValueProto()); + EXPECT_FALSE(basic_interactions_.ComputeValue(proto)); + + // Multi value fails. + ValueProto multi_value; + multi_value.mutable_booleans()->add_values(true); + multi_value.mutable_booleans()->add_values(false); + user_model_.SetValue("value", multi_value); + EXPECT_FALSE(basic_interactions_.ComputeValue(proto)); +} + TEST_F(BasicInteractionsTest, EndActionWithoutCallbackFails) { EndActionProto proto; ASSERT_DEATH(basic_interactions_.EndAction(proto),
diff --git a/components/autofill_assistant/browser/interactions.proto b/components/autofill_assistant/browser/interactions.proto index 460c88ae..c390f55 100644 --- a/components/autofill_assistant/browser/interactions.proto +++ b/components/autofill_assistant/browser/interactions.proto
@@ -35,6 +35,7 @@ SetUserActionsProto set_user_actions = 5; EndActionProto end_action = 6; ShowCalendarPopupProto show_calendar_popup = 7; + SetTextProto set_text = 8; } } @@ -81,6 +82,8 @@ BooleanOrProto boolean_or = 3; // Computes the logical NOT of the specified model identifiers. BooleanNotProto boolean_not = 4; + // Creates a string representation of the specified value. + ToStringProto to_string = 5; } // The model identifier to write the result to. @@ -107,6 +110,21 @@ optional string model_identifier = 1; } +// Creates a string representation of the specified value. +message ToStringProto { + // The model identifier to stringify. + optional string model_identifier = 1; + + // Optional format options. + oneof format_options { DateFormatProto date_format = 2; } +} + +// A format string for a date, such as "EEE, MMM d". See +// http://userguide.icu-project.org/formatparse/datetime for full specification. +message DateFormatProto { + optional string date_format = 1; +} + // Displays a standard info popup. message ShowInfoPopupProto { optional InfoPopupProto info_popup = 1; @@ -134,6 +152,9 @@ optional string selected_item_indices_model_identifier = 3; // Whether to allow the selection of multiple items or not. optional bool allow_multiselect = 4; + // Optional output model identifier to store the names of the selected items + // in a StringList. + optional string selected_item_names_model_identifier = 5; } // Sets the list of available user actions. User actions are either direct @@ -166,3 +187,12 @@ // DateList. optional string max_date_model_identifier = 3; } + +// Modifies the displayed text of a text view. +message SetTextProto { + // The model identifier containing the text to set. Must point to a single + // string. + optional string model_identifier = 1; + // The text view to modify. Must point to a text view. + optional string view_identifier = 2; +}
diff --git a/components/external_intents/android/BUILD.gn b/components/external_intents/android/BUILD.gn index f12ab019..52ade7e 100644 --- a/components/external_intents/android/BUILD.gn +++ b/components/external_intents/android/BUILD.gn
@@ -6,8 +6,31 @@ android_library("java") { sources = [ + "java/src/org/chromium/components/external_intents/ExternalIntentsFeatureList.java", "java/src/org/chromium/components/external_intents/ExternalIntentsSwitches.java", "java/src/org/chromium/components/external_intents/ExternalNavigationParams.java", "java/src/org/chromium/components/external_intents/RedirectHandler.java", ] + + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] + deps = [ + "//base:base_java", + "//base:jni_java", + ] +} + +generate_jni("jni_headers") { + sources = [ "java/src/org/chromium/components/external_intents/ExternalIntentsFeatureList.java" ] +} + +static_library("android") { + sources = [ + "external_intents_feature_list.cc", + "external_intents_feature_list.h", + ] + + deps = [ + ":jni_headers", + "//base", + ] }
diff --git a/components/external_intents/android/external_intents_feature_list.cc b/components/external_intents/android/external_intents_feature_list.cc new file mode 100644 index 0000000..e442aca --- /dev/null +++ b/components/external_intents/android/external_intents_feature_list.cc
@@ -0,0 +1,53 @@ +// Copyright 2020 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/external_intents/android/external_intents_feature_list.h" + +#include <jni.h> +#include <stddef.h> +#include <string> + +#include "base/android/jni_string.h" +#include "components/external_intents/android/jni_headers/ExternalIntentsFeatureList_jni.h" + +namespace external_intents { + +namespace { + +// Array of features exposed through the Java ExternalIntentsFeatureList API. +const base::Feature* kFeaturesExposedToJava[] = { + &kIntentBlockExternalFormRedirectsNoGesture, +}; + +const base::Feature* FindFeatureExposedToJava(const std::string& feature_name) { + for (const auto* feature : kFeaturesExposedToJava) { + if (feature->name == feature_name) + return feature; + } + NOTREACHED() + << "Queried feature cannot be found in ExternalIntentsFeatureList: " + << feature_name; + return nullptr; +} + +} // namespace + +// Alphabetical: +const base::Feature kIntentBlockExternalFormRedirectsNoGesture{ + "IntentBlockExternalFormRedirectsNoGesture", + base::FEATURE_DISABLED_BY_DEFAULT}; + +static jboolean JNI_ExternalIntentsFeatureList_IsInitialized(JNIEnv* env) { + return !!base::FeatureList::GetInstance(); +} + +static jboolean JNI_ExternalIntentsFeatureList_IsEnabled( + JNIEnv* env, + const base::android::JavaParamRef<jstring>& jfeature_name) { + const base::Feature* feature = FindFeatureExposedToJava( + base::android::ConvertJavaStringToUTF8(env, jfeature_name)); + return base::FeatureList::IsEnabled(*feature); +} + +} // namespace external_intents
diff --git a/components/external_intents/android/external_intents_feature_list.h b/components/external_intents/android/external_intents_feature_list.h new file mode 100644 index 0000000..02388aa --- /dev/null +++ b/components/external_intents/android/external_intents_feature_list.h
@@ -0,0 +1,17 @@ +// Copyright 2020 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_EXTERNAL_INTENTS_ANDROID_EXTERNAL_INTENTS_FEATURE_LIST_H_ +#define COMPONENTS_EXTERNAL_INTENTS_ANDROID_EXTERNAL_INTENTS_FEATURE_LIST_H_ + +#include "base/feature_list.h" + +namespace external_intents { + +// Alphabetical: +extern const base::Feature kIntentBlockExternalFormRedirectsNoGesture; + +} // namespace external_intents + +#endif // COMPONENTS_EXTERNAL_INTENTS_ANDROID_EXTERNAL_INTENTS_FEATURE_LIST_H_
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalIntentsFeatureList.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalIntentsFeatureList.java new file mode 100644 index 0000000..96cf47df --- /dev/null +++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalIntentsFeatureList.java
@@ -0,0 +1,70 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.external_intents; + +import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.MainDex; +import org.chromium.base.annotations.NativeMethods; +import org.chromium.base.library_loader.LibraryLoader; + +/** + * Java accessor for base/feature_list.h state. + * + * This class provides methods to access values of feature flags registered in + * |kFeaturesExposedToJava| in components/external_intents/android/external_intents_feature_list.cc. + * + */ +@JNINamespace("external_intents") +@MainDex +public abstract class ExternalIntentsFeatureList { + /** Prevent instantiation. */ + private ExternalIntentsFeatureList() {} + + /** + * @return Whether the native FeatureList is initialized or not. + */ + private static boolean isNativeInitialized() { + if (!LibraryLoader.getInstance().isInitialized()) return false; + // Even if the native library is loaded, the C++ FeatureList might not be initialized yet. + // In that case, accessing it will not immediately fail, but instead cause a crash later + // when it is initialized. Return whether the native FeatureList has been initialized, + // so the return value can be tested, or asserted for a more actionable stack trace + // on failure. + // + // The FeatureList is however guaranteed to be initialized by the time + // AsyncInitializationActivity#finishNativeInitialization is called. + return ExternalIntentsFeatureListJni.get().isInitialized(); + } + + /** + * Returns whether the specified feature is enabled or not. + * + * Note: Features queried through this API must be added to the array + * |kFeaturesExposedToJava| in + * components/external_intents/android/external_intents_feature_list.cc. + * + * Calling this has the side effect of bucketing this client, which may cause an experiment to + * be marked as active. + * + * Should be called only after native is loaded. + * + * @param featureName The name of the feature to query. + * @return Whether the feature is enabled or not. + */ + public static boolean isEnabled(String featureName) { + assert isNativeInitialized(); + return ExternalIntentsFeatureListJni.get().isEnabled(featureName); + } + + /** Alphabetical: */ + public static final String INTENT_BLOCK_EXTERNAL_FORM_REDIRECT_NO_GESTURE = + "IntentBlockExternalFormRedirectsNoGesture"; + + @NativeMethods + interface Natives { + boolean isInitialized(); + boolean isEnabled(String featureName); + } +}
diff --git a/components/favicon/core/history_ui_favicon_request_handler.h b/components/favicon/core/history_ui_favicon_request_handler.h index 0a774c2..50fcc2ae 100644 --- a/components/favicon/core/history_ui_favicon_request_handler.h +++ b/components/favicon/core/history_ui_favicon_request_handler.h
@@ -23,16 +23,16 @@ }; // Keyed service for handling favicon requests made by a history UI, forwarding -// them to local storage, sync or Google server accordingly. This service should +// them to local storage or Google server accordingly. This service should // only be used by the UIs listed in the HistoryUiFaviconRequestOrigin enum. // Requests must be made by page url, as opposed to icon url. class HistoryUiFaviconRequestHandler : public KeyedService { public: // Requests favicon bitmap at |page_url| of size |desired_size_in_pixel|. - // Tries to fetch the icon from local storage and falls back to sync, or the - // Google favicon server if user settings allow to query it using history - // data. If a non-empty |icon_url_for_uma| (optional) is passed, it will - // be used to record UMA about the grouping of requests to the favicon server. + // Tries to fetch the icon from local storage and falls back to the Google + // favicon server if user settings allow to query it using history data. + // If a non-empty |icon_url_for_uma| (optional) is passed, it will be used to + // record UMA about the grouping of requests to the favicon server. virtual void GetRawFaviconForPageURL( const GURL& page_url, int desired_size_in_pixel, @@ -40,12 +40,8 @@ HistoryUiFaviconRequestOrigin request_origin_for_uma, const GURL& icon_url_for_uma) = 0; - // Requests favicon image at |page_url|. - // Tries to fetch the icon from local storage and falls back to sync, or the - // Google favicon server if user settings allow to query it using history - // data. - // If a non-empty |icon_url_for_uma| (optional) is passed, it will be used to - // record UMA about the grouping of requests to the favicon server. + // Requests favicon image at |page_url|. The same fallback considerations for + // GetRawFaviconForPageURL apply. // This method is only called by desktop code. virtual void GetFaviconImageForPageURL( const GURL& page_url,
diff --git a/components/favicon/core/history_ui_favicon_request_handler_impl.cc b/components/favicon/core/history_ui_favicon_request_handler_impl.cc index c112f4a..8051b2d4 100644 --- a/components/favicon/core/history_ui_favicon_request_handler_impl.cc +++ b/components/favicon/core/history_ui_favicon_request_handler_impl.cc
@@ -97,13 +97,11 @@ } // namespace HistoryUiFaviconRequestHandlerImpl::HistoryUiFaviconRequestHandlerImpl( - const SyncedFaviconGetter& synced_favicon_getter, const CanSendHistoryDataGetter& can_send_history_data_getter, FaviconService* favicon_service, LargeIconService* large_icon_service) : favicon_service_(favicon_service), large_icon_service_(large_icon_service), - synced_favicon_getter_(synced_favicon_getter), can_send_history_data_getter_(can_send_history_data_getter) { DCHECK(favicon_service); DCHECK(large_icon_service); @@ -186,19 +184,7 @@ return; } - favicon_base::FaviconRawBitmapResult sync_bitmap_result = - synced_favicon_getter_.Run(page_url); - if (sync_bitmap_result.is_valid()) { - // If request to sync succeeds, resize bitmap to desired size and send. - RecordFaviconAvailabilityAndLatencyMetric( - origin_for_uma, request_start_time_for_uma, FaviconAvailability::kSync); - std::move(response_callback) - .Run(favicon_base::ResizeFaviconBitmapResult({sync_bitmap_result}, - desired_size_in_pixel)); - return; - } - - // If sync does not have the favicon, send empty response. + // Send empty response. RecordFaviconAvailabilityAndLatencyMetric(origin_for_uma, request_start_time_for_uma, FaviconAvailability::kNotAvailable); @@ -246,21 +232,7 @@ return; } - favicon_base::FaviconRawBitmapResult sync_bitmap_result = - synced_favicon_getter_.Run(page_url); - if (sync_bitmap_result.is_valid()) { - // If request to sync succeeds, convert the retrieved bitmap to image and - // send. - RecordFaviconAvailabilityAndLatencyMetric( - origin_for_uma, request_start_time_for_uma, FaviconAvailability::kSync); - favicon_base::FaviconImageResult sync_image_result; - sync_image_result.image = - gfx::Image::CreateFrom1xPNGBytes(sync_bitmap_result.bitmap_data.get()); - std::move(response_callback).Run(sync_image_result); - return; - } - - // If sync does not have the favicon, send empty response. + // Send empty response. RecordFaviconAvailabilityAndLatencyMetric(origin_for_uma, request_start_time_for_uma, FaviconAvailability::kNotAvailable);
diff --git a/components/favicon/core/history_ui_favicon_request_handler_impl.h b/components/favicon/core/history_ui_favicon_request_handler_impl.h index 71a3be4..e9bbd04 100644 --- a/components/favicon/core/history_ui_favicon_request_handler_impl.h +++ b/components/favicon/core/history_ui_favicon_request_handler_impl.h
@@ -22,8 +22,9 @@ enum class FaviconAvailability { // Icon recovered from local storage (but may originally come from server). kLocal = 0, + // DEPRECATED: No icon is retrieved using sync in this layer anymore. // Icon recovered using sync. - kSync = 1, + kDeprecatedSync = 1, // Icon not found. kNotAvailable = 2, kMaxValue = kNotAvailable, @@ -33,18 +34,12 @@ class HistoryUiFaviconRequestHandlerImpl : public HistoryUiFaviconRequestHandler { public: - // Callback that requests the synced bitmap for a page url. - using SyncedFaviconGetter = - base::RepeatingCallback<favicon_base::FaviconRawBitmapResult( - const GURL&)>; - // Callback that checks whether user settings allow to query the favicon // server using history data (in particular it must check that history sync is // enabled and no custom passphrase is set). using CanSendHistoryDataGetter = base::RepeatingCallback<bool()>; HistoryUiFaviconRequestHandlerImpl( - const SyncedFaviconGetter& synced_favicon_getter, const CanSendHistoryDataGetter& can_send_history_data_getter, FaviconService* favicon_service, LargeIconService* large_icon_service); @@ -65,9 +60,9 @@ private: // Called after the first attempt to retrieve the icon bitmap from local - // storage. If request succeeded, sends the result. Otherwise attempts to - // retrieve from sync or the Google favicon server depending on the result - // given by |can_send_history_data_getter_|. + // storage. If request succeeded, sends the result. Otherwise, if allowed by + // user settings, (i.e. if |can_send_history_data_getter_| returns true), + // attempts to retrieve from the Google favicon server. void OnBitmapLocalDataAvailable( const GURL& page_url, int desired_size_in_pixel, @@ -78,9 +73,9 @@ const favicon_base::FaviconRawBitmapResult& bitmap_result); // Called after the first attempt to retrieve the icon image from local - // storage. If request succeeded, sends the result. Otherwise attempts to - // retrieve from sync or the Google favicon server depending on the result - // given by |can_send_history_data_getter_|. + // storage. If request succeeded, sends the result. Otherwise, if allowed by + // user settings, (i.e. if |can_send_history_data_getter_| returns true), + // attempts to retrieve from the Google favicon server. void OnImageLocalDataAvailable( const GURL& page_url, favicon_base::FaviconImageCallback response_callback, @@ -117,8 +112,6 @@ LargeIconService* const large_icon_service_; - SyncedFaviconGetter const synced_favicon_getter_; - CanSendHistoryDataGetter const can_send_history_data_getter_; // Map from a group identifier to the number of callbacks in that group which
diff --git a/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc b/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc index d0bfd83d..22a1a405 100644 --- a/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc +++ b/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc
@@ -211,27 +211,17 @@ public: HistoryUiFaviconRequestHandlerImplTest() : mock_large_icon_service_(&mock_favicon_service_), - history_ui_favicon_request_handler_(synced_favicon_getter_.Get(), - can_send_history_data_getter_.Get(), + history_ui_favicon_request_handler_(can_send_history_data_getter_.Get(), &mock_favicon_service_, &mock_large_icon_service_) { // Allow sending history data by default. ON_CALL(can_send_history_data_getter_, Run()).WillByDefault(Return(true)); - - // Sync will by default respond it does not contain any icon. Same is done - // for the FaviconService and LargeIconService fakes in their constructors. - ON_CALL(synced_favicon_getter_, Run(_)).WillByDefault([](auto) { - return favicon_base::FaviconRawBitmapResult(); - }); } protected: testing::NiceMock<MockFaviconServiceWithFake> mock_favicon_service_; testing::NiceMock<MockLargeIconServiceWithFake> mock_large_icon_service_; testing::NiceMock<base::MockCallback< - HistoryUiFaviconRequestHandlerImpl::SyncedFaviconGetter>> - synced_favicon_getter_; - testing::NiceMock<base::MockCallback< HistoryUiFaviconRequestHandlerImpl::CanSendHistoryDataGetter>> can_send_history_data_getter_; base::HistogramTester histogram_tester_; @@ -245,7 +235,6 @@ EXPECT_CALL(mock_favicon_service_, GetRawFaviconForPageURL(GURL(kDummyPageUrl), _, kDefaultDesiredSizeInPixel, _, _, _)); - EXPECT_CALL(synced_favicon_getter_, Run(_)).Times(0); favicon_base::FaviconRawBitmapResult result; history_ui_favicon_request_handler_.GetRawFaviconForPageURL( GURL(kDummyPageUrl), kDefaultDesiredSizeInPixel, @@ -259,26 +248,6 @@ std::string(kLatencyHistogramName) + kDummyOriginHistogramSuffix, 1); } -TEST_F(HistoryUiFaviconRequestHandlerImplTest, ShouldGetSyncBitmap) { - ON_CALL(can_send_history_data_getter_, Run()).WillByDefault(Return(false)); - EXPECT_CALL(mock_favicon_service_, - GetRawFaviconForPageURL(GURL(kDummyPageUrl), _, - kDefaultDesiredSizeInPixel, _, _, _)); - EXPECT_CALL(synced_favicon_getter_, Run(GURL(kDummyPageUrl))) - .WillOnce([](auto) { return CreateTestBitmapResult(); }); - favicon_base::FaviconRawBitmapResult result; - history_ui_favicon_request_handler_.GetRawFaviconForPageURL( - GURL(kDummyPageUrl), kDefaultDesiredSizeInPixel, - base::BindOnce(&StoreBitmap, &result), kDummyOrigin, - /*icon_url_for_uma=*/GURL()); - EXPECT_TRUE(result.is_valid()); - histogram_tester_.ExpectUniqueSample( - std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix, - FaviconAvailability::kSync, 1); - histogram_tester_.ExpectTotalCount( - std::string(kLatencyHistogramName) + kDummyOriginHistogramSuffix, 1); -} - TEST_F(HistoryUiFaviconRequestHandlerImplTest, ShouldGetLocalBitmap) { mock_favicon_service_.StoreMockLocalFavicon(GURL(kDummyPageUrl)); EXPECT_CALL(mock_favicon_service_, @@ -286,7 +255,6 @@ kDefaultDesiredSizeInPixel, _, _, _)); EXPECT_CALL(mock_large_icon_service_, TouchIconFromGoogleServer(GURL(kDummyIconUrl))); - EXPECT_CALL(synced_favicon_getter_, Run(_)).Times(0); favicon_base::FaviconRawBitmapResult result; history_ui_favicon_request_handler_.GetRawFaviconForPageURL( GURL(kDummyPageUrl), kDefaultDesiredSizeInPixel, @@ -329,7 +297,6 @@ TEST_F(HistoryUiFaviconRequestHandlerImplTest, ShouldGetEmptyImage) { EXPECT_CALL(mock_favicon_service_, GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, _)); - EXPECT_CALL(synced_favicon_getter_, Run(_)).Times(0); favicon_base::FaviconImageResult result; history_ui_favicon_request_handler_.GetFaviconImageForPageURL( GURL(kDummyPageUrl), base::BindOnce(&StoreImage, &result), kDummyOrigin, @@ -342,31 +309,12 @@ std::string(kLatencyHistogramName) + kDummyOriginHistogramSuffix, 1); } -TEST_F(HistoryUiFaviconRequestHandlerImplTest, ShouldGetSyncImage) { - ON_CALL(can_send_history_data_getter_, Run()).WillByDefault(Return(false)); - EXPECT_CALL(mock_favicon_service_, - GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, _)); - EXPECT_CALL(synced_favicon_getter_, Run(GURL(kDummyPageUrl))) - .WillOnce([](auto) { return CreateTestBitmapResult(); }); - favicon_base::FaviconImageResult result; - history_ui_favicon_request_handler_.GetFaviconImageForPageURL( - GURL(kDummyPageUrl), base::BindOnce(&StoreImage, &result), kDummyOrigin, - /*icon_url_for_uma=*/GURL()); - EXPECT_FALSE(result.image.IsEmpty()); - histogram_tester_.ExpectUniqueSample( - std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix, - FaviconAvailability::kSync, 1); - histogram_tester_.ExpectTotalCount( - std::string(kLatencyHistogramName) + kDummyOriginHistogramSuffix, 1); -} - TEST_F(HistoryUiFaviconRequestHandlerImplTest, ShouldGetLocalImage) { mock_favicon_service_.StoreMockLocalFavicon(GURL(kDummyPageUrl)); EXPECT_CALL(mock_favicon_service_, GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, _)); EXPECT_CALL(mock_large_icon_service_, TouchIconFromGoogleServer(GURL(kDummyIconUrl))); - EXPECT_CALL(synced_favicon_getter_, Run(_)).Times(0); favicon_base::FaviconImageResult result; history_ui_favicon_request_handler_.GetFaviconImageForPageURL( GURL(kDummyPageUrl), base::BindOnce(&StoreImage, &result), kDummyOrigin, @@ -389,7 +337,6 @@ GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache( GURL(kDummyPageUrl), _, /*should_trim_url_path=*/false, _, _)); - EXPECT_CALL(synced_favicon_getter_, Run(_)).Times(0); favicon_base::FaviconImageResult result; history_ui_favicon_request_handler_.GetFaviconImageForPageURL( GURL(kDummyPageUrl), base::BindOnce(&StoreImage, &result), kDummyOrigin, @@ -428,29 +375,5 @@ /*icon_url_for_uma=*/GURL()); } -TEST_F(HistoryUiFaviconRequestHandlerImplTest, ShouldResizeSyncBitmap) { - const int kDesiredSizeInPixel = 32; - ON_CALL(can_send_history_data_getter_, Run()).WillByDefault(Return(false)); - EXPECT_CALL(mock_favicon_service_, - GetRawFaviconForPageURL(GURL(kDummyPageUrl), _, - kDesiredSizeInPixel, _, _, _)) - .WillOnce([](auto, auto, auto, auto, - favicon_base::FaviconRawBitmapCallback callback, auto) { - std::move(callback).Run(favicon_base::FaviconRawBitmapResult()); - return kDummyTaskId; - }); - // Have sync return bitmap of different size from the one requested. - EXPECT_CALL(synced_favicon_getter_, Run(GURL(kDummyPageUrl))) - .WillOnce([](auto) { return CreateTestBitmapResult(16); }); - favicon_base::FaviconRawBitmapResult result; - history_ui_favicon_request_handler_.GetRawFaviconForPageURL( - GURL(kDummyPageUrl), kDesiredSizeInPixel, - base::BindOnce(&StoreBitmap, &result), kDummyOrigin, - /*icon_url_for_uma=*/GURL()); - EXPECT_TRUE(result.is_valid()); - EXPECT_EQ(gfx::Size(kDesiredSizeInPixel, kDesiredSizeInPixel), - result.pixel_size); -} - } // namespace } // namespace favicon
diff --git a/components/gwp_asan/client/guarded_page_allocator.cc b/components/gwp_asan/client/guarded_page_allocator.cc index eb82ef0..3c1bc44 100644 --- a/components/gwp_asan/client/guarded_page_allocator.cc +++ b/components/gwp_asan/client/guarded_page_allocator.cc
@@ -347,8 +347,9 @@ if (!oom_hit_) { if (++consecutive_failed_allocations_ == kOutOfMemoryCount) { oom_hit_ = true; + size_t allocations = total_allocations_ - kOutOfMemoryCount; base::AutoUnlock unlock(lock_); - std::move(oom_callback_).Run(total_allocations_ - kOutOfMemoryCount); + std::move(oom_callback_).Run(allocations); } } return false;
diff --git a/components/password_manager/core/browser/leak_detection_delegate.cc b/components/password_manager/core/browser/leak_detection_delegate.cc index 35061e84..07e6569 100644 --- a/components/password_manager/core/browser/leak_detection_delegate.cc +++ b/components/password_manager/core/browser/leak_detection_delegate.cc
@@ -28,8 +28,9 @@ using Logger = autofill::SavePasswordProgressLogger; -void LogString(PasswordManagerClient* client, Logger::StringID string_id) { - if (password_manager_util::IsLoggingActive(client)) { +void LogString(const PasswordManagerClient* client, + Logger::StringID string_id) { + if (client && password_manager_util::IsLoggingActive(client)) { BrowserSavePasswordProgressLogger logger(client->GetLogManager()); logger.LogMessage(string_id); } @@ -47,37 +48,8 @@ if (client_->IsIncognito()) return; - bool is_leak_protection_on = client_->GetPrefs()->GetBoolean( - password_manager::prefs::kPasswordLeakDetectionEnabled); - - // Leak detection can only start if: - // 1. The user has not opted out and Safe Browsing is turned on, or - // 2. The user is an enhanced protection user - // Safe Browsing is only available on non-IOS. -#if defined(OS_IOS) - if (!is_leak_protection_on) { - LogString(client_, Logger::STRING_LEAK_DETECTION_DISABLED_FEATURE); + if (!CanStartLeakCheck(*client_->GetPrefs(), client_)) return; - } -#else - safe_browsing::SafeBrowsingState sb_state = - safe_browsing::GetSafeBrowsingState(*client_->GetPrefs()); - switch (sb_state) { - case safe_browsing::NO_SAFE_BROWSING: - LogString(client_, Logger::STRING_LEAK_DETECTION_DISABLED_SAFE_BROWSING); - return; - case safe_browsing::STANDARD_PROTECTION: - if (!is_leak_protection_on) { - LogString(client_, Logger::STRING_LEAK_DETECTION_DISABLED_FEATURE); - return; - } - // feature is on. - break; - case safe_browsing::ENHANCED_PROTECTION: - // feature is on. - break; - } -#endif if (form.username_value.empty()) return; @@ -156,4 +128,37 @@ } } +bool CanStartLeakCheck(const PrefService& prefs, + const PasswordManagerClient* client) { + const bool is_leak_protection_on = + prefs.GetBoolean(password_manager::prefs::kPasswordLeakDetectionEnabled); + + // Leak detection can only start if: + // 1. The user has not opted out and Safe Browsing is turned on, or + // 2. The user is an enhanced protection user + // Safe Browsing is only available on non-IOS. +#if defined(OS_IOS) + if (!is_leak_protection_on) + LogString(client, Logger::STRING_LEAK_DETECTION_DISABLED_FEATURE); + return is_leak_protection_on; +#else + safe_browsing::SafeBrowsingState sb_state = + safe_browsing::GetSafeBrowsingState(prefs); + switch (sb_state) { + case safe_browsing::NO_SAFE_BROWSING: + LogString(client, Logger::STRING_LEAK_DETECTION_DISABLED_SAFE_BROWSING); + return false; + case safe_browsing::STANDARD_PROTECTION: + if (!is_leak_protection_on) + LogString(client, Logger::STRING_LEAK_DETECTION_DISABLED_FEATURE); + return is_leak_protection_on; + case safe_browsing::ENHANCED_PROTECTION: + // feature is on. + break; + } + + return true; +#endif +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection_delegate.h b/components/password_manager/core/browser/leak_detection_delegate.h index 3822690..d74bce3 100644 --- a/components/password_manager/core/browser/leak_detection_delegate.h +++ b/components/password_manager/core/browser/leak_detection_delegate.h
@@ -17,6 +17,8 @@ struct PasswordForm; } // namespace autofill +class PrefService; + namespace password_manager { class LeakDetectionCheck; @@ -77,6 +79,11 @@ std::unique_ptr<LeakDetectionDelegateHelper> helper_; }; +// Determines whether the leak check can be started depending on |prefs|. Will +// use |client| for logging if non-null. +bool CanStartLeakCheck(const PrefService& prefs, + const PasswordManagerClient* client = nullptr); + } // namespace password_manager #endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_DELEGATE_H_
diff --git a/components/password_manager/core/browser/leak_detection_delegate_unittest.cc b/components/password_manager/core/browser/leak_detection_delegate_unittest.cc index 8c428fa..3933d5a 100644 --- a/components/password_manager/core/browser/leak_detection_delegate_unittest.cc +++ b/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
@@ -207,6 +207,7 @@ delegate().StartLeakCheck(form); EXPECT_TRUE(delegate().leak_check()); + EXPECT_TRUE(CanStartLeakCheck(*pref_service())); } TEST_F(LeakDetectionDelegateTest, StartCheckWithEnhancedProtection) { @@ -225,6 +226,7 @@ delegate().StartLeakCheck(form); EXPECT_TRUE(delegate().leak_check()); + EXPECT_TRUE(CanStartLeakCheck(*pref_service())); } TEST_F(LeakDetectionDelegateTest, DoNotStartCheckWithoutSafeBrowsing) { @@ -237,6 +239,7 @@ delegate().StartLeakCheck(form); EXPECT_FALSE(delegate().leak_check()); + EXPECT_FALSE(CanStartLeakCheck(*pref_service())); } TEST_F(LeakDetectionDelegateTest, DoNotStartLeakCheckIfLeakCheckIsOff) { @@ -249,6 +252,7 @@ delegate().StartLeakCheck(form); EXPECT_FALSE(delegate().leak_check()); + EXPECT_FALSE(CanStartLeakCheck(*pref_service())); } #endif
diff --git a/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.cc b/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.cc index 3add05b3..95eed08 100644 --- a/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.cc +++ b/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.cc
@@ -12,7 +12,9 @@ #include "components/autofill/core/common/password_form.h" #include "components/password_manager/core/browser/leak_detection/bulk_leak_check.h" #include "components/password_manager/core/browser/leak_detection/encryption_utils.h" +#include "components/password_manager/core/browser/leak_detection_delegate.h" #include "components/password_manager/core/browser/ui/saved_passwords_presenter.h" +#include "components/prefs/pref_service.h" namespace password_manager { @@ -41,10 +43,12 @@ BulkLeakCheckServiceAdapter::BulkLeakCheckServiceAdapter( SavedPasswordsPresenter* presenter, - BulkLeakCheckService* service) - : presenter_(presenter), service_(service) { + BulkLeakCheckService* service, + PrefService* prefs) + : presenter_(presenter), service_(service), prefs_(prefs) { DCHECK(presenter_); DCHECK(service_); + DCHECK(prefs_); presenter_->AddObserver(this); } @@ -91,11 +95,13 @@ } void BulkLeakCheckServiceAdapter::OnEdited(const PasswordForm& form) { - // Here no extra canonicalization is needed, as there are no other forms we - // could de-dupe before we pass it on to the service. - std::vector<LeakCheckCredential> credentials; - credentials.emplace_back(form.username_value, form.password_value); - service_->CheckUsernamePasswordPairs(std::move(credentials)); + if (CanStartLeakCheck(*prefs_)) { + // Here no extra canonicalization is needed, as there are no other forms we + // could de-dupe before we pass it on to the service. + std::vector<LeakCheckCredential> credentials; + credentials.emplace_back(form.username_value, form.password_value); + service_->CheckUsernamePasswordPairs(std::move(credentials)); + } } } // namespace password_manager
diff --git a/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h b/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h index 29923115..bd2c6ab 100644 --- a/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h +++ b/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h
@@ -13,6 +13,8 @@ struct PasswordForm; } +class PrefService; + namespace password_manager { // This class serves as an apdater for the BulkLeakCheckService and exposes an @@ -20,7 +22,8 @@ class BulkLeakCheckServiceAdapter : public SavedPasswordsPresenter::Observer { public: BulkLeakCheckServiceAdapter(SavedPasswordsPresenter* presenter, - BulkLeakCheckService* service); + BulkLeakCheckService* service, + PrefService* prefs); ~BulkLeakCheckServiceAdapter() override; // Instructs the adapter to start a check. This is a no-op in case a check is @@ -47,6 +50,8 @@ // null and must outlive the adapter. SavedPasswordsPresenter* presenter_ = nullptr; BulkLeakCheckService* service_ = nullptr; + + PrefService* prefs_ = nullptr; }; } // namespace password_manager
diff --git a/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter_unittest.cc b/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter_unittest.cc index b6630c1..a31030b1d 100644 --- a/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter_unittest.cc +++ b/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter_unittest.cc
@@ -20,6 +20,10 @@ #include "components/password_manager/core/browser/leak_detection/mock_leak_detection_check_factory.h" #include "components/password_manager/core/browser/test_password_store.h" #include "components/password_manager/core/browser/ui/saved_passwords_presenter.h" +#include "components/password_manager/core/common/password_manager_pref_names.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/testing_pref_service.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "components/sync/model/syncable_service.h" #include "services/network/test/test_shared_url_loader_factory.h" @@ -95,6 +99,11 @@ service_.set_leak_factory(std::move(factory)); store_->Init(syncer::SyncableService::StartSyncFlare(), /*prefs=*/nullptr); + prefs_.registry()->RegisterBooleanPref(prefs::kPasswordLeakDetectionEnabled, + true); + prefs_.registry()->RegisterBooleanPref(::prefs::kSafeBrowsingEnabled, true); + prefs_.registry()->RegisterBooleanPref(::prefs::kSafeBrowsingEnhanced, + false); } ~BulkLeakCheckServiceAdapterTest() override { @@ -105,6 +114,7 @@ TestPasswordStore& store() { return *store_; } SavedPasswordsPresenter& presenter() { return presenter_; } MockLeakDetectionCheckFactory& factory() { return *factory_; } + PrefService& prefs() { return prefs_; } BulkLeakCheckServiceAdapter& adapter() { return adapter_; } void RunUntilIdle() { task_env_.RunUntilIdle(); } @@ -119,7 +129,8 @@ identity_test_env_.identity_manager(), base::MakeRefCounted<network::TestSharedURLLoaderFactory>()}; MockLeakDetectionCheckFactory* factory_ = nullptr; - BulkLeakCheckServiceAdapter adapter_{&presenter_, &service_}; + TestingPrefServiceSimple prefs_; + BulkLeakCheckServiceAdapter adapter_{&presenter_, &service_, &prefs_}; }; } // namespace @@ -216,9 +227,26 @@ adapter().GetBulkLeakCheckState()); } +// Tests that editing a password through the presenter does not result in +// another call to CheckCredentials with a corresponding change to the checked +// password if the corresponding prefs are not set. +TEST_F(BulkLeakCheckServiceAdapterTest, OnEditedNoPrefs) { + prefs().SetBoolean(prefs::kPasswordLeakDetectionEnabled, false); + prefs().SetBoolean(::prefs::kSafeBrowsingEnabled, false); + + PasswordForm password = + MakeSavedPassword(kExampleCom, kUsername1, kPassword1); + store().AddLogin(password); + RunUntilIdle(); + + EXPECT_CALL(factory(), TryCreateBulkLeakCheck).Times(0); + presenter().EditPassword(password, base::ASCIIToUTF16(kPassword2)); +} + // Tests that editing a password through the presenter will result in another -// call to CheckCredentials with a corresponding change to the checked password. -TEST_F(BulkLeakCheckServiceAdapterTest, OnEdited) { +// call to CheckCredentials with a corresponding change to the checked password +// if the corresponding prefs are set. +TEST_F(BulkLeakCheckServiceAdapterTest, OnEditedWithPrefs) { PasswordForm password = MakeSavedPassword(kExampleCom, kUsername1, kPassword1); store().AddLogin(password);
diff --git a/components/payments/content/installable_payment_app_crawler.cc b/components/payments/content/installable_payment_app_crawler.cc index ee78b07..bce2884 100644 --- a/components/payments/content/installable_payment_app_crawler.cc +++ b/components/payments/content/installable_payment_app_crawler.cc
@@ -15,10 +15,13 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/global_routing_id.h" #include "content/public/browser/manifest_icon_downloader.h" #include "content/public/browser/payment_app_provider.h" #include "content/public/browser/permission_controller.h" #include "content/public/browser/permission_type.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "third_party/blink/public/common/manifest/manifest.h" @@ -33,6 +36,7 @@ // TODO(crbug.com/782270): Add integration tests for this class. InstallablePaymentAppCrawler::InstallablePaymentAppCrawler( const url::Origin& merchant_origin, + content::RenderFrameHost* initiator_render_frame_host, content::WebContents* web_contents, PaymentManifestDownloader* downloader, PaymentManifestParser* parser, @@ -40,6 +44,7 @@ : WebContentsObserver(web_contents), log_(web_contents), merchant_origin_(merchant_origin), + initiator_render_frame_host_(initiator_render_frame_host), downloader_(downloader), parser_(parser), number_of_payment_method_manifest_to_download_(0), @@ -401,6 +406,13 @@ } number_of_web_app_icons_to_download_and_decode_++; + + content::GlobalFrameRoutingId frame_routing_id; + if (initiator_render_frame_host_) { + frame_routing_id = content::GlobalFrameRoutingId( + initiator_render_frame_host_->GetProcess()->GetID(), + initiator_render_frame_host_->GetRoutingID()); + } bool can_download_icon = content::ManifestIconDownloader::Download( web_contents(), downloader_->FindTestServerURL(best_icon_url), IconSizeCalculator::IdealIconHeight(native_view), @@ -409,7 +421,8 @@ &InstallablePaymentAppCrawler::OnPaymentWebAppIconDownloadAndDecoded, weak_ptr_factory_.GetWeakPtr(), method_manifest_url, web_app_manifest_url), - false /* square_only */); + false, /* square_only */ + frame_routing_id); DCHECK(can_download_icon); }
diff --git a/components/payments/content/installable_payment_app_crawler.h b/components/payments/content/installable_payment_app_crawler.h index cad6cb6..fdad1391 100644 --- a/components/payments/content/installable_payment_app_crawler.h +++ b/components/payments/content/installable_payment_app_crawler.h
@@ -26,6 +26,7 @@ class GURL; namespace content { +class RenderFrameHost; class WebContents; } @@ -40,18 +41,21 @@ std::map<GURL, std::unique_ptr<WebAppInstallationInfo>>, const std::string& error_message)>; - // |merchant_origin| should be the origin of the iframe that created the + // |merchant_origin| is the origin of the iframe that created the // PaymentRequest object. It is used by security features like // 'Sec-Fetch-Site' and 'Cross-Origin-Resource-Policy'. + // |initiator_render_frame_host| is the iframe for |merchant_origin|. // // The owner of InstallablePaymentAppCrawler owns |downloader|, |parser| and // |cache|. They should live until |finished_using_resources| parameter to // Start() method is called. - InstallablePaymentAppCrawler(const url::Origin& merchant_origin, - content::WebContents* web_contents, - PaymentManifestDownloader* downloader, - PaymentManifestParser* parser, - PaymentManifestWebDataService* cache); + InstallablePaymentAppCrawler( + const url::Origin& merchant_origin, + content::RenderFrameHost* initiator_render_frame_host, + content::WebContents* web_contents, + PaymentManifestDownloader* downloader, + PaymentManifestParser* parser, + PaymentManifestWebDataService* cache); ~InstallablePaymentAppCrawler() override; // Starts the crawling process. All the url based payment methods in @@ -107,6 +111,7 @@ DeveloperConsoleLogger log_; const url::Origin merchant_origin_; + content::RenderFrameHost* initiator_render_frame_host_; PaymentManifestDownloader* downloader_; PaymentManifestParser* parser_; FinishedCrawlingCallback callback_;
diff --git a/components/payments/content/payment_app_factory.h b/components/payments/content/payment_app_factory.h index 281dbe6..a33a2c55 100644 --- a/components/payments/content/payment_app_factory.h +++ b/components/payments/content/payment_app_factory.h
@@ -21,6 +21,7 @@ } // namespace autofill namespace content { +class RenderFrameHost; class WebContents; } // namespace content @@ -46,6 +47,7 @@ virtual const GURL& GetTopOrigin() = 0; virtual const GURL& GetFrameOrigin() = 0; virtual const url::Origin& GetFrameSecurityOrigin() = 0; + virtual content::RenderFrameHost* GetInitiatorRenderFrameHost() const = 0; virtual const std::vector<autofill::AutofillProfile*>& GetBillingProfiles() = 0; virtual bool IsRequestedAutofillDataAvailable() = 0;
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc index fae8e9e..cc9c24e 100644 --- a/components/payments/content/payment_request.cc +++ b/components/payments/content/payment_request.cc
@@ -97,6 +97,7 @@ mojo::PendingReceiver<mojom::PaymentRequest> receiver, ObserverForTest* observer_for_testing) : web_contents_(web_contents), + initiator_render_frame_host_(render_frame_host), log_(web_contents_), delegate_(std::move(delegate)), manager_(manager), @@ -186,8 +187,8 @@ std::move(options), std::move(details), std::move(method_data), /*observer=*/this, delegate_->GetApplicationLocale()); state_ = std::make_unique<PaymentRequestState>( - web_contents_, top_level_origin_, frame_origin_, frame_security_origin_, - spec_.get(), + web_contents_, initiator_render_frame_host_, top_level_origin_, + frame_origin_, frame_security_origin_, spec_.get(), /*delegate=*/this, delegate_->GetApplicationLocale(), delegate_->GetPersonalDataManager(), delegate_.get(), base::BindRepeating(&PaymentRequest::SetInvokedServiceWorkerIdentity,
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h index 3e8b289..18ec889 100644 --- a/components/payments/content/payment_request.h +++ b/components/payments/content/payment_request.h
@@ -184,6 +184,7 @@ bool warn_localhost_or_file); content::WebContents* web_contents_; + content::RenderFrameHost* initiator_render_frame_host_; DeveloperConsoleLogger log_; std::unique_ptr<ContentPaymentRequestDelegate> delegate_; // |manager_| owns this PaymentRequest.
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc index 6240af7..65dbd1a 100644 --- a/components/payments/content/payment_request_state.cc +++ b/components/payments/content/payment_request_state.cc
@@ -33,6 +33,7 @@ #include "components/payments/core/payment_app.h" #include "components/payments/core/payment_request_data_util.h" #include "components/payments/core/payments_experimental_features.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/common/content_features.h" namespace payments { @@ -56,6 +57,7 @@ PaymentRequestState::PaymentRequestState( content::WebContents* web_contents, + content::RenderFrameHost* initiator_render_frame_host, const GURL& top_level_origin, const GURL& frame_origin, const url::Origin& frame_security_origin, @@ -67,6 +69,7 @@ const ServiceWorkerPaymentApp::IdentityCallback& sw_identity_callback, JourneyLogger* journey_logger) : web_contents_(web_contents), + initiator_render_frame_host_(initiator_render_frame_host), top_origin_(top_level_origin), frame_origin_(frame_origin), frame_security_origin_(frame_security_origin), @@ -118,6 +121,11 @@ return frame_security_origin_; } +content::RenderFrameHost* PaymentRequestState::GetInitiatorRenderFrameHost() + const { + return initiator_render_frame_host_; +} + const std::vector<autofill::AutofillProfile*>& PaymentRequestState::GetBillingProfiles() { return shipping_profiles_;
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h index 9d61e98..3fbf03d 100644 --- a/components/payments/content/payment_request_state.h +++ b/components/payments/content/payment_request_state.h
@@ -33,6 +33,10 @@ class RegionDataLoader; } // namespace autofill +namespace content { +class RenderFrameHost; +} // namespace content + namespace payments { class ContentPaymentRequestDelegate; @@ -112,6 +116,7 @@ PaymentRequestState( content::WebContents* web_contents, + content::RenderFrameHost* initiator_render_frame_host, const GURL& top_level_origin, const GURL& frame_origin, const url::Origin& frame_security_origin, @@ -131,6 +136,7 @@ const GURL& GetTopOrigin() override; const GURL& GetFrameOrigin() override; const url::Origin& GetFrameSecurityOrigin() override; + content::RenderFrameHost* GetInitiatorRenderFrameHost() const override; const std::vector<autofill::AutofillProfile*>& GetBillingProfiles() override; bool IsRequestedAutofillDataAvailable() override; bool MayCrawlForInstallablePaymentApps() override; @@ -336,6 +342,7 @@ SectionSelectionStatus selection_status); content::WebContents* web_contents_; + content::RenderFrameHost* initiator_render_frame_host_; const GURL top_origin_; const GURL frame_origin_; const url::Origin frame_security_origin_;
diff --git a/components/payments/content/payment_request_state_unittest.cc b/components/payments/content/payment_request_state_unittest.cc index 1c57423..76f8f1a 100644 --- a/components/payments/content/payment_request_state_unittest.cc +++ b/components/payments/content/payment_request_state_unittest.cc
@@ -80,7 +80,8 @@ PaymentAppServiceFactory::SetForTesting( std::make_unique<PaymentAppService>()); state_ = std::make_unique<PaymentRequestState>( - /*web_contents=*/nullptr, GURL("https://example.com"), + /*web_contents=*/nullptr, + /*render_frame_host=*/nullptr, GURL("https://example.com"), GURL("https://example.com/pay"), url::Origin::Create(GURL("https://example.com")), spec_.get(), this, "en-US", &test_personal_data_manager_, &test_payment_request_delegate_,
diff --git a/components/payments/content/service_worker_payment_app_factory.cc b/components/payments/content/service_worker_payment_app_factory.cc index 66c0d9c..0e86a59 100644 --- a/components/payments/content/service_worker_payment_app_factory.cc +++ b/components/payments/content/service_worker_payment_app_factory.cc
@@ -126,7 +126,8 @@ ServiceWorkerPaymentAppCreator* creator_raw_pointer = creator.get(); creators_[creator_raw_pointer] = std::move(creator); ServiceWorkerPaymentAppFinder::GetInstance()->GetAllPaymentApps( - delegate->GetFrameSecurityOrigin(), delegate->GetWebContents(), + delegate->GetFrameSecurityOrigin(), + delegate->GetInitiatorRenderFrameHost(), delegate->GetWebContents(), delegate->GetPaymentRequestDelegate()->GetPaymentManifestWebDataService(), delegate->GetSpec()->method_data(), delegate->MayCrawlForInstallablePaymentApps(),
diff --git a/components/payments/content/service_worker_payment_app_finder.cc b/components/payments/content/service_worker_payment_app_finder.cc index f67f435b..25fd140 100644 --- a/components/payments/content/service_worker_payment_app_finder.cc +++ b/components/payments/content/service_worker_payment_app_finder.cc
@@ -24,6 +24,7 @@ #include "components/payments/core/payment_manifest_downloader.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/stored_payment_app.h" #include "content/public/browser/web_contents.h" @@ -99,6 +100,7 @@ // until |finished_using_resources_callback| has run. void GetAllPaymentApps( const url::Origin& merchant_origin, + content::RenderFrameHost* initiator_render_frame_host, content::WebContents* web_contents, std::unique_ptr<PaymentManifestDownloader> downloader, scoped_refptr<PaymentManifestWebDataService> cache, @@ -120,8 +122,8 @@ features::kWebPaymentsJustInTimePaymentApp)) { // Construct crawler in constructor to allow it observe the web_contents. crawler_ = std::make_unique<InstallablePaymentAppCrawler>( - merchant_origin, web_contents, downloader_.get(), parser_.get(), - cache_.get()); + merchant_origin, initiator_render_frame_host, web_contents, + downloader_.get(), parser_.get(), cache_.get()); if (ignore_port_in_origin_comparison_for_testing_) crawler_->IgnorePortInOriginComparisonForTesting(); } @@ -284,6 +286,7 @@ void ServiceWorkerPaymentAppFinder::GetAllPaymentApps( const url::Origin& merchant_origin, + content::RenderFrameHost* initiator_render_frame_host, content::WebContents* web_contents, scoped_refptr<PaymentManifestWebDataService> cache, const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data, @@ -306,9 +309,9 @@ } self_delete_factory->GetAllPaymentApps( - merchant_origin, web_contents, std::move(downloader), cache, - requested_method_data, may_crawl_for_installable_payment_apps, - std::move(callback), + merchant_origin, initiator_render_frame_host, web_contents, + std::move(downloader), cache, requested_method_data, + may_crawl_for_installable_payment_apps, std::move(callback), std::move(finished_writing_cache_callback_for_testing)); }
diff --git a/components/payments/content/service_worker_payment_app_finder.h b/components/payments/content/service_worker_payment_app_finder.h index afc68c1..f05730f 100644 --- a/components/payments/content/service_worker_payment_app_finder.h +++ b/components/payments/content/service_worker_payment_app_finder.h
@@ -27,6 +27,7 @@ } // namespace base namespace content { +class RenderFrameHost; class WebContents; } // namespace content @@ -70,6 +71,7 @@ // The method should be called on the UI thread. void GetAllPaymentApps( const url::Origin& merchant_origin, + content::RenderFrameHost* initiator_render_frame_host, content::WebContents* web_contents, scoped_refptr<PaymentManifestWebDataService> cache, const std::vector<mojom::PaymentMethodDataPtr>& requested_method_data,
diff --git a/components/performance_manager/graph/process_node_impl.cc b/components/performance_manager/graph/process_node_impl.cc index 8fc6caf..f2f52e9 100644 --- a/components/performance_manager/graph/process_node_impl.cc +++ b/components/performance_manager/graph/process_node_impl.cc
@@ -22,6 +22,10 @@ ProcessNodeImpl::~ProcessNodeImpl() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // Crash if this process node is destroyed while still hosting a worker node. + // TODO(https://crbug.com/1058705): Turn this into a DCHECK once the issue is + // resolved. + CHECK(worker_nodes_.empty()); } void ProcessNodeImpl::Bind(
diff --git a/components/policy/core/common/cloud/enterprise_metrics.cc b/components/policy/core/common/cloud/enterprise_metrics.cc index 035fc39..835bae3be 100644 --- a/components/policy/core/common/cloud/enterprise_metrics.cc +++ b/components/policy/core/common/cloud/enterprise_metrics.cc
@@ -41,4 +41,12 @@ const char kMetricPolicyInvalidationRegistrationFcm[] = "Enterprise.FCMInvalidationService.PolicyInvalidationsRegistrationResult"; +const char kMetricUserRemoteCommandInvalidations[] = + "Enterprise.UserRemoteCommandInvalidations"; +const char kMetricDeviceRemoteCommandInvalidations[] = + "Enterprise.DeviceRemoteCommandInvalidations"; + +const char kMetricRemoteCommandInvalidationsRegistrationResult[] = + "Enterprise.RemoteCommandInvalidationsRegistrationResult"; + } // namespace policy
diff --git a/components/policy/core/common/cloud/enterprise_metrics.h b/components/policy/core/common/cloud/enterprise_metrics.h index e06edd2e..90b55b7 100644 --- a/components/policy/core/common/cloud/enterprise_metrics.h +++ b/components/policy/core/common/cloud/enterprise_metrics.h
@@ -244,6 +244,12 @@ POLICY_EXPORT extern const char kMetricPolicyInvalidationRegistration[]; POLICY_EXPORT extern const char kMetricPolicyInvalidationRegistrationFcm[]; +POLICY_EXPORT extern const char kMetricUserRemoteCommandInvalidations[]; +POLICY_EXPORT extern const char kMetricDeviceRemoteCommandInvalidations[]; + +POLICY_EXPORT extern const char + kMetricRemoteCommandInvalidationsRegistrationResult[]; + } // namespace policy #endif // COMPONENTS_POLICY_CORE_COMMON_CLOUD_ENTERPRISE_METRICS_H_
diff --git a/components/safe_browsing/core/db/v4_local_database_manager.cc b/components/safe_browsing/core/db/v4_local_database_manager.cc index d58fffe..c16b552f 100644 --- a/components/safe_browsing/core/db/v4_local_database_manager.cc +++ b/components/safe_browsing/core/db/v4_local_database_manager.cc
@@ -188,6 +188,21 @@ COUNT, }; +void RecordTimeSinceLastUpdateHistograms(const base::Time& last_response_time) { + bool response_received = !last_response_time.is_null(); + UMA_HISTOGRAM_BOOLEAN( + "SafeBrowsing.V4LocalDatabaseManager.HasReceivedUpdateResponse", + response_received); + + if (!response_received) + return; + + base::TimeDelta time_since_update = base::Time::Now() - last_response_time; + UMA_HISTOGRAM_LONG_TIMES_100( + "SafeBrowsing.V4LocalDatabaseManager.TimeSinceLastUpdateResponse", + time_since_update); +} + } // namespace V4LocalDatabaseManager::PendingCheck::PendingCheck( @@ -335,6 +350,8 @@ bool safe_synchronously = HandleCheck(std::move(check)); UMA_HISTOGRAM_BOOLEAN("SafeBrowsing.CheckBrowseUrl.HasLocalMatch", !safe_synchronously); + RecordTimeSinceLastUpdateHistograms( + v4_update_protocol_manager_->last_response_time()); return safe_synchronously; }
diff --git a/components/safe_browsing/core/db/v4_update_protocol_manager.cc b/components/safe_browsing/core/db/v4_update_protocol_manager.cc index e4a6f6a..c36864b 100644 --- a/components/safe_browsing/core/db/v4_update_protocol_manager.cc +++ b/components/safe_browsing/core/db/v4_update_protocol_manager.cc
@@ -449,4 +449,8 @@ } } +const base::Time& V4UpdateProtocolManager::last_response_time() const { + return last_response_time_; +} + } // namespace safe_browsing
diff --git a/components/safe_browsing/core/db/v4_update_protocol_manager.h b/components/safe_browsing/core/db/v4_update_protocol_manager.h index e1cc1bc7..068b245 100644 --- a/components/safe_browsing/core/db/v4_update_protocol_manager.h +++ b/components/safe_browsing/core/db/v4_update_protocol_manager.h
@@ -73,6 +73,10 @@ // Populates the UpdateInfo message. void CollectUpdateInfo(DatabaseManagerInfo::UpdateInfo* database_info); + // The time that a response was last received from the server. This will + // have a null value if no response has been received. + const base::Time& last_response_time() const; + protected: // Constructs a V4UpdateProtocolManager that issues network requests using // |url_loader_factory|. It schedules updates to get the hash prefixes for
diff --git a/components/services/storage/indexed_db/leveldb/leveldb_state.cc b/components/services/storage/indexed_db/leveldb/leveldb_state.cc index cfd009f4..c2f1275 100644 --- a/components/services/storage/indexed_db/leveldb/leveldb_state.cc +++ b/components/services/storage/indexed_db/leveldb/leveldb_state.cc
@@ -4,8 +4,10 @@ #include "components/services/storage/indexed_db/leveldb/leveldb_state.h" +#include "base/location.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_functions.h" +#include "base/synchronization/waitable_event.h" #include "third_party/leveldatabase/src/include/leveldb/env.h" namespace content { @@ -43,24 +45,20 @@ name_for_tracing_(std::move(name_for_tracing)), destruction_requested_(false) {} -bool LevelDBState::RequestDestruction( - base::OnceClosure on_state_destruction, - scoped_refptr<base::SequencedTaskRunner> task_runner) { - if (destruction_requested_.exchange(true, std::memory_order_relaxed)) - return false; - - DCHECK(!on_destruction_); - DCHECK(!on_destruction_task_runner_); - on_destruction_ = std::move(on_state_destruction); - on_destruction_task_runner_ = std::move(task_runner); - return true; +void LevelDBState::RequestDestruction( + base::WaitableEvent* signal_on_destruction) { + DCHECK(signal_on_destruction); + bool destruct_already_requested = + destruction_requested_.exchange(true, std::memory_order_relaxed); + CHECK(!destruct_already_requested) + << "RequestDestruction can only be called one time."; + DCHECK(!signal_on_destruction_); + signal_on_destruction_ = signal_on_destruction; } LevelDBState::~LevelDBState() { - if (on_destruction_) { - on_destruction_task_runner_->PostTask(FROM_HERE, - std::move(on_destruction_)); - } + if (signal_on_destruction_) + signal_on_destruction_->Signal(); if (!db_) return; base::TimeTicks begin_time = base::TimeTicks::Now();
diff --git a/components/services/storage/indexed_db/leveldb/leveldb_state.h b/components/services/storage/indexed_db/leveldb/leveldb_state.h index 044f8c7..e2bfa1bb 100644 --- a/components/services/storage/indexed_db/leveldb/leveldb_state.h +++ b/components/services/storage/indexed_db/leveldb/leveldb_state.h
@@ -9,15 +9,17 @@ #include <memory> #include <utility> -#include "base/callback.h" #include "base/files/file_path.h" #include "base/memory/ref_counted.h" -#include "base/memory/scoped_refptr.h" #include "base/sequenced_task_runner.h" #include "third_party/leveldatabase/src/include/leveldb/comparator.h" #include "third_party/leveldatabase/src/include/leveldb/db.h" #include "third_party/leveldatabase/src/include/leveldb/filter_policy.h" +namespace base { +class WaitableEvent; +} // namespace base + namespace content { // Encapsulates a leveldb database and comparator, allowing them to be used @@ -35,16 +37,18 @@ std::unique_ptr<leveldb::DB> in_memory_database, std::string name_for_tracing); - // Returns if this call was successfully the first call to request destruction - // of this state. Can be called on any thread. The given |task_runner| will be - // used to call the |on_destruction| closure, which is called on the - // destruction of this state. - bool RequestDestruction(base::OnceClosure on_destruction, - scoped_refptr<base::SequencedTaskRunner> task_runner); + // Can only be called once. |signal_on_destruction| must outlive this class, + // and will be signaled on the destruction of this state (in the destructor). + // Can be called on any thread. + void RequestDestruction(base::WaitableEvent* signal_on_destruction); bool destruction_requested() const { return destruction_requested_.load(std::memory_order_relaxed); } + // Only valid if destruction_requested() returns true. + base::WaitableEvent* destruction_event() const { + return signal_on_destruction_; + } const leveldb::Comparator* comparator() const { return comparator_; } leveldb::DB* db() const { return db_.get(); } @@ -74,11 +78,10 @@ // This member transitions from false to true at most once in the instance's // lifetime. std::atomic_bool destruction_requested_; - // These members are written only once (when |destruction_requested_| - // transitions from false to true) and read only once in the destructor, so - // they are thread-compatible. - base::OnceClosure on_destruction_; - scoped_refptr<base::SequencedTaskRunner> on_destruction_task_runner_; + // |signal_on_destruction_| is written only once (when + // |destruction_requested_| transitions from false to true) and read only once + // in the destructor, so it is thread-compatible. + base::WaitableEvent* signal_on_destruction_ = nullptr; }; } // namespace content
diff --git a/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks_unittest.cc b/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks_unittest.cc index 697b902..8905a11f7 100644 --- a/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks_unittest.cc +++ b/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks_unittest.cc
@@ -139,8 +139,7 @@ CleanupScopeTask::CleanupMode::kExecuteCleanupTasks, kWriteBatchSizeForTesting); - leveldb_->RequestDestruction(base::DoNothing(), - base::SequencedTaskRunnerHandle::Get()); + leveldb_->RequestDestruction(&leveldb_close_event_); leveldb::Status s = task.Run(); ASSERT_TRUE(s.ok()) << s.ToString(); EXPECT_TRUE(LoadAt(delete_range_start_key_).ok());
diff --git a/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc b/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc index c290cef5..bb1605f 100644 --- a/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc +++ b/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc
@@ -9,6 +9,7 @@ #include "base/run_loop.h" #include "base/sequenced_task_runner.h" #include "base/strings/stringprintf.h" +#include "base/synchronization/waitable_event_watcher.h" #include "base/system/sys_info.h" #include "base/test/bind_test_util.h" #include "base/threading/sequenced_task_runner_handle.h" @@ -64,12 +65,26 @@ void LevelDBScopesTestBase::CloseScopesAndDestroyLevelDBState() { if (leveldb_) { base::RunLoop loop; - if (leveldb_->RequestDestruction(loop.QuitClosure(), - base::SequencedTaskRunnerHandle::Get())) { - leveldb_.reset(); - loop.Run(); + base::WaitableEvent* leveldb_close_event_ptr; + base::WaitableEventWatcher event_watcher; + if (leveldb_->destruction_requested()) { + leveldb_close_event_ptr = leveldb_->destruction_event(); + } else { + leveldb_close_event_ptr = &leveldb_close_event_; + leveldb_->RequestDestruction(leveldb_close_event_ptr); } + event_watcher.StartWatching( + leveldb_close_event_ptr, + base::BindLambdaForTesting([&](base::WaitableEvent*) { loop.Quit(); }), + base::SequencedTaskRunnerHandle::Get()); leveldb_.reset(); + loop.Run(); + // There is a possible race in |leveldb_close_event| where the signaling + // thread is still in the WaitableEvent::Signal() method. To ensure that + // the other thread exits their Signal method, any method on the + // WaitableEvent can be called to acquire the internal lock (which will + // subsequently wait for the other thread to exit the Signal method). + EXPECT_TRUE(leveldb_close_event_ptr->IsSignaled()); } }
diff --git a/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.h b/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.h index 0cad1d3..7538df3c 100644 --- a/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.h +++ b/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.h
@@ -103,6 +103,8 @@ // may need to run cleanup tasks that close files residing in the former. base::ScopedTempDir temp_directory_; base::test::TaskEnvironment task_env_; + // For use with calling leveldb_->RequestDestruction(...); + base::WaitableEvent leveldb_close_event_; const std::string simple_lock_begin_ = "0000000001"; const std::string simple_lock_end_ = "0000000010";
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index e10cad9..962d24e 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -43,7 +43,7 @@ deps = [ "//base", "//base:base_static", - "//base:clang_coverage_buildflags", + "//base:clang_profiling_buildflags", "//base/third_party/dynamic_annotations", "//build:branding_buildflags", "//cc",
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc index ab64a262..fad3fc5 100644 --- a/content/browser/accessibility/accessibility_win_browsertest.cc +++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -48,6 +48,7 @@ #include "third_party/iaccessible2/ia2_api_all.h" #include "third_party/isimpledom/ISimpleDOMNode.h" #include "ui/accessibility/accessibility_switches.h" +#include "ui/accessibility/ax_event_generator.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" @@ -907,10 +908,42 @@ } // namespace +// // Tests ---------------------------------------------------------------------- +// + +IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, + TestAlwaysFireFocusEventAfterNavigationComplete) { + ASSERT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL))); + + // Users of Jaws or NVDA screen readers might not realize that the virtual + // buffer has been loaded, if focus hasn't been placed in the document after + // navigating to a new page. If a focus event is not received by the screen + // reader, it might "think" that focus is outside the web contents. + // + // We can't use "LoadInitialAccessibilityTreeFromHtml" because it waits for + // the "kLoadComplete" event, and the "kFocus" and "kLoadComplete" events are + // not guaranteed to be sent in the same order every time, neither do we need + // to enforce such an ordering. However, we do need to ensure that at the + // point when the "kFocus" event is sent, the document is fully loaded. + AccessibilityNotificationWaiter waiter( + shell()->web_contents(), ui::kAXModeComplete, + ui::AXEventGenerator::Event::FOCUS_CHANGED); + GURL html_data_url("data:text/html,<p>Hello world.</p>"); + ASSERT_TRUE(NavigateToURL(shell(), html_data_url)); + waiter.WaitForNotification(); + + // Check that the page has indeed loaded. + AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L""); + AccessibleChecker paragraph_checker(L"", L"P", IA2_ROLE_PARAGRAPH, L""); + document_checker.AppendExpectedChild(¶graph_checker); + AccessibleChecker text_checker(L"Hello world.", ROLE_SYSTEM_STATICTEXT, L""); + paragraph_checker.AppendExpectedChild(&text_checker); + document_checker.CheckAccessible(GetRendererAccessible()); +} IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, TestBusyAccessibilityTree) { - EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL))); + ASSERT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL))); // The initial accessible returned should have state STATE_SYSTEM_BUSY while // the accessibility tree is being requested from the renderer.
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc index 589673f..cf6d248f 100644 --- a/content/browser/browser_interface_binders.cc +++ b/content/browser/browser_interface_binders.cc
@@ -327,30 +327,6 @@ base::Unretained(host), method); } -template <typename WorkerHost, typename Interface> -base::RepeatingCallback<void(const url::Origin&, - mojo::PendingReceiver<Interface>)> -BindWorkerReceiverForOriginAndCOEP( - void (RenderProcessHost::*method)(const network::CrossOriginEmbedderPolicy&, - const url::Origin&, - mojo::PendingReceiver<Interface>), - WorkerHost* host, - const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy) { - return base::BindRepeating( - [](WorkerHost* host, - void (RenderProcessHost::*method)( - const network::CrossOriginEmbedderPolicy&, const url::Origin&, - mojo::PendingReceiver<Interface>), - const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy, - const url::Origin& origin, mojo::PendingReceiver<Interface> receiver) { - RenderProcessHost* process_host = host->GetProcessHost(); - if (process_host) - (process_host->*method)(cross_origin_embedder_policy, origin, - std::move(receiver)); - }, - base::Unretained(host), method, cross_origin_embedder_policy); -} - template <typename... Args> void RunOrPostTaskToBindServiceWorkerReceiver( ServiceWorkerProviderHost* host, @@ -428,33 +404,6 @@ } template <typename Interface> -base::RepeatingCallback<void(const ServiceWorkerVersionInfo&, - mojo::PendingReceiver<Interface>)> -BindServiceWorkerReceiverForOriginAndCOEP( - void (RenderProcessHost::*method)(const network::CrossOriginEmbedderPolicy&, - const url::Origin&, - mojo::PendingReceiver<Interface>), - ServiceWorkerProviderHost* host, - const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy) { - return base::BindRepeating( - [](ServiceWorkerProviderHost* host, - void (RenderProcessHost::*method)( - const network::CrossOriginEmbedderPolicy&, const url::Origin&, - mojo::PendingReceiver<Interface>), - const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy, - const ServiceWorkerVersionInfo& info, - mojo::PendingReceiver<Interface> receiver) { - auto origin = info.script_origin; - RunOrPostTaskToBindServiceWorkerReceiver< - const network::CrossOriginEmbedderPolicy&, const url::Origin&, - mojo::PendingReceiver<Interface>>(host, method, - cross_origin_embedder_policy, - origin, std::move(receiver)); - }, - base::Unretained(host), method, cross_origin_embedder_policy); -} - -template <typename Interface> void EmptyBinderForFrame(RenderFrameHost* host, mojo::PendingReceiver<Interface> receiver) { DLOG(ERROR) << "Empty binder for interface " << Interface::Name_ @@ -790,6 +739,8 @@ map->Add<blink::mojom::QuicTransportConnector>( base::BindRepeating(&DedicatedWorkerHost::CreateQuicTransportConnector, base::Unretained(host))); + map->Add<blink::mojom::CacheStorage>(base::BindRepeating( + &DedicatedWorkerHost::BindCacheStorage, base::Unretained(host))); #if !defined(OS_ANDROID) map->Add<blink::mojom::SerialService>(base::BindRepeating( &DedicatedWorkerHost::BindSerialService, base::Unretained(host))); @@ -825,12 +776,6 @@ map->Add<blink::mojom::QuotaDispatcherHost>( BindWorkerReceiverForOriginAndFrameId( &RenderProcessHost::BindQuotaDispatcherHost, host)); - - // render process host binders taking a Cross-Origin-Embedder-Policy and an - // origin. - map->Add<blink::mojom::CacheStorage>(BindWorkerReceiverForOriginAndCOEP( - &RenderProcessHost::BindCacheStorage, host, - host->cross_origin_embedder_policy())); } void PopulateBinderMap(DedicatedWorkerHost* host, @@ -866,6 +811,8 @@ &SharedWorkerHost::CreateAppCacheBackend, base::Unretained(host))); map->Add<blink::mojom::QuicTransportConnector>(base::BindRepeating( &SharedWorkerHost::CreateQuicTransportConnector, base::Unretained(host))); + map->Add<blink::mojom::CacheStorage>(base::BindRepeating( + &SharedWorkerHost::BindCacheStorage, base::Unretained(host))); // render process host binders map->Add<media::mojom::VideoDecodePerfHistory>( @@ -899,14 +846,6 @@ map->Add<blink::mojom::QuotaDispatcherHost>( BindWorkerReceiverForOriginAndFrameId( &RenderProcessHost::BindQuotaDispatcherHost, host)); - - // render process host binders taking a Cross-Origin-Embedder-Policy and an - // origin. - // TODO(https://crbug.com/1031542): Add support enforcing CORP in - // cache.match() for SharedWorker - map->Add<blink::mojom::CacheStorage>(BindWorkerReceiverForOriginAndCOEP( - &RenderProcessHost::BindCacheStorage, host, - network::CrossOriginEmbedderPolicy())); } void PopulateBinderMap(SharedWorkerHost* host, @@ -943,6 +882,8 @@ map->Add<blink::mojom::QuicTransportConnector>(base::BindRepeating( &ServiceWorkerProviderHost::CreateQuicTransportConnector, base::Unretained(host))); + map->Add<blink::mojom::CacheStorage>(base::BindRepeating( + &ServiceWorkerProviderHost::BindCacheStorage, base::Unretained(host))); map->Add<blink::mojom::BadgeService>( base::BindRepeating(&BindBadgeServiceForServiceWorker, host)); @@ -1009,15 +950,6 @@ map->Add<blink::mojom::QuotaDispatcherHost>( BindServiceWorkerReceiverForOriginAndFrameId( &RenderProcessHost::BindQuotaDispatcherHost, host)); - - // render process host bind taking a Cross-Origin-Embedder-Policy and an - // origin. - // TODO(https://crbug.com/1031542): Add support enforcing CORP in - // cache.match() for ServiceWorker - map->Add<blink::mojom::CacheStorage>( - BindServiceWorkerReceiverForOriginAndCOEP( - &RenderProcessHost::BindCacheStorage, host, - network::CrossOriginEmbedderPolicy())); } void PopulateBinderMap(ServiceWorkerProviderHost* host,
diff --git a/content/browser/browser_process_sub_thread.cc b/content/browser/browser_process_sub_thread.cc index 70dd877..f7c731e 100644 --- a/content/browser/browser_process_sub_thread.cc +++ b/content/browser/browser_process_sub_thread.cc
@@ -5,7 +5,7 @@ #include "content/browser/browser_process_sub_thread.h" #include "base/bind.h" -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/compiler_specific.h" #include "base/debug/alias.h" #include "base/metrics/histogram_macros.h" @@ -162,8 +162,8 @@ service_manager::SandboxType::kNetwork) { // This ensures that cookies and cache are flushed to disk on shutdown. // https://crbug.com/841001 -#if BUILDFLAG(CLANG_COVERAGE) - // On coverage build, browser_tests runs 10x slower. +#if BUILDFLAG(CLANG_PROFILING) + // On profiling build, browser_tests runs 10x slower. const int kMaxSecondsToWaitForNetworkProcess = 100; #elif defined(OS_CHROMEOS) // ChromeOS will kill the browser process if it doesn't shut down within
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index 757a82d..57d627b 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -7,7 +7,7 @@ #include <utility> #include "base/bind.h" -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/command_line.h" #include "base/files/file_util.h" #include "base/i18n/icu_util.h" @@ -43,7 +43,7 @@ start_time_(base::TimeTicks::Now()), #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ - defined(UNDEFINED_SANITIZER) || BUILDFLAG(CLANG_COVERAGE) + defined(UNDEFINED_SANITIZER) || BUILDFLAG(CLANG_PROFILING) terminate_child_on_shutdown_(false) #else terminate_child_on_shutdown_(terminate_on_shutdown)
diff --git a/content/browser/child_process_task_port_provider_mac_unittest.cc b/content/browser/child_process_task_port_provider_mac_unittest.cc index 3f0c02d2..ed599f76 100644 --- a/content/browser/child_process_task_port_provider_mac_unittest.cc +++ b/content/browser/child_process_task_port_provider_mac_unittest.cc
@@ -8,7 +8,7 @@ #include <vector> -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/mac/scoped_mach_port.h" #include "base/synchronization/waitable_event.h" #include "base/task/post_task.h" @@ -35,8 +35,8 @@ #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED) MOCK_METHOD1(SetIPCLoggingEnabled, void(bool)); #endif -#if BUILDFLAG(CLANG_COVERAGE_INSIDE_SANDBOX) - MOCK_METHOD1(SetCoverageFile, void(base::File)); +#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) + MOCK_METHOD1(SetProfilingFile, void(base::File)); #endif MOCK_METHOD1(GetBackgroundTracingAgentProvider, void(mojo::PendingReceiver<
diff --git a/content/browser/devtools/service_worker_devtools_agent_host.cc b/content/browser/devtools/service_worker_devtools_agent_host.cc index 111f2afa..02c8487 100644 --- a/content/browser/devtools/service_worker_devtools_agent_host.cc +++ b/content/browser/devtools/service_worker_devtools_agent_host.cc
@@ -71,6 +71,8 @@ const GURL& url, const GURL& scope, bool is_installed_version, + base::Optional<network::CrossOriginEmbedderPolicy> + cross_origin_embedder_policy, const base::UnguessableToken& devtools_worker_token) : DevToolsAgentHostImpl(devtools_worker_token.ToString()), state_(WORKER_NOT_READY), @@ -83,7 +85,8 @@ url_(url), scope_(scope), version_installed_time_(is_installed_version ? base::Time::Now() - : base::Time()) { + : base::Time()), + cross_origin_embedder_policy_(std::move(cross_origin_embedder_policy)) { NotifyCreated(); } @@ -173,6 +176,11 @@ UpdateIsAttached(true); } +void ServiceWorkerDevToolsAgentHost::UpdateCrossOriginEmbedderPolicy( + network::CrossOriginEmbedderPolicy cross_origin_embedder_policy) { + cross_origin_embedder_policy_ = std::move(cross_origin_embedder_policy); +} + void ServiceWorkerDevToolsAgentHost::WorkerRestarted(int worker_process_id, int worker_route_id) { DCHECK_EQ(WORKER_TERMINATED, state_); @@ -206,13 +214,20 @@ return; } const url::Origin origin = url::Origin::Create(url_); - // TODO(https://crbug.com/1039613): Get the COEP for the service worker - // and pass it to each factory bundle. + + // Use the default CrossOriginEmbedderPolicy if + // |cross_origin_embedder_policy_| is nullopt. It's acceptable because the + // factory bundles are updated with correct COEP value before any subresource + // requests in that case. auto script_bundle = EmbeddedWorkerInstance::CreateFactoryBundleOnUI( - rph, worker_route_id_, origin, network::CrossOriginEmbedderPolicy(), + rph, worker_route_id_, origin, + cross_origin_embedder_policy_ ? cross_origin_embedder_policy_.value() + : network::CrossOriginEmbedderPolicy(), ContentBrowserClient::URLLoaderFactoryType::kServiceWorkerScript); auto subresource_bundle = EmbeddedWorkerInstance::CreateFactoryBundleOnUI( - rph, worker_route_id_, origin, network::CrossOriginEmbedderPolicy(), + rph, worker_route_id_, origin, + cross_origin_embedder_policy_ ? cross_origin_embedder_policy_.value() + : network::CrossOriginEmbedderPolicy(), ContentBrowserClient::URLLoaderFactoryType::kServiceWorkerSubResource); if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
diff --git a/content/browser/devtools/service_worker_devtools_agent_host.h b/content/browser/devtools/service_worker_devtools_agent_host.h index aa33022..b2bc1ce 100644 --- a/content/browser/devtools/service_worker_devtools_agent_host.h +++ b/content/browser/devtools/service_worker_devtools_agent_host.h
@@ -14,6 +14,7 @@ #include "base/unguessable_token.h" #include "content/browser/devtools/devtools_agent_host_impl.h" #include "content/browser/devtools/service_worker_devtools_manager.h" +#include "services/network/public/cpp/cross_origin_embedder_policy.h" #include "third_party/blink/public/mojom/devtools/devtools_agent.mojom.h" namespace content { @@ -35,6 +36,8 @@ const GURL& url, const GURL& scope, bool is_installed_version, + base::Optional<network::CrossOriginEmbedderPolicy> + cross_origin_embedder_policy, const base::UnguessableToken& devtools_worker_token); // DevToolsAgentHost overrides. @@ -50,6 +53,8 @@ void WorkerReadyForInspection( mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote, mojo::PendingReceiver<blink::mojom::DevToolsAgentHost> host_receiver); + void UpdateCrossOriginEmbedderPolicy( + network::CrossOriginEmbedderPolicy cross_origin_embedder_policy); void WorkerDestroyed(); void WorkerVersionInstalled(); void WorkerVersionDoomed(); @@ -97,6 +102,8 @@ GURL scope_; base::Time version_installed_time_; base::Time version_doomed_time_; + base::Optional<network::CrossOriginEmbedderPolicy> + cross_origin_embedder_policy_; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDevToolsAgentHost); };
diff --git a/content/browser/devtools/service_worker_devtools_manager.cc b/content/browser/devtools/service_worker_devtools_manager.cc index 19f53dab..442c93d6 100644 --- a/content/browser/devtools/service_worker_devtools_manager.cc +++ b/content/browser/devtools/service_worker_devtools_manager.cc
@@ -52,6 +52,8 @@ const GURL& url, const GURL& scope, bool is_installed_version, + base::Optional<network::CrossOriginEmbedderPolicy> + cross_origin_embedder_policy, base::UnguessableToken* devtools_worker_token, bool* pause_on_start) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -66,10 +68,10 @@ if (it == terminated_hosts_.end()) { *devtools_worker_token = base::UnguessableToken::Create(); scoped_refptr<ServiceWorkerDevToolsAgentHost> host = - new ServiceWorkerDevToolsAgentHost(worker_process_id, worker_route_id, - context, context_weak, version_id, - url, scope, is_installed_version, - *devtools_worker_token); + new ServiceWorkerDevToolsAgentHost( + worker_process_id, worker_route_id, context, context_weak, + version_id, url, scope, is_installed_version, + cross_origin_embedder_policy, *devtools_worker_token); live_hosts_[worker_id] = host; *pause_on_start = debug_service_worker_on_start_; for (auto& observer : observer_list_) { @@ -107,6 +109,20 @@ host->Inspect(); } +void ServiceWorkerDevToolsManager::UpdateCrossOriginEmbedderPolicy( + int worker_process_id, + int worker_route_id, + network::CrossOriginEmbedderPolicy cross_origin_embedder_policy) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + const WorkerId worker_id(worker_process_id, worker_route_id); + auto it = live_hosts_.find(worker_id); + if (it == live_hosts_.end()) + return; + scoped_refptr<ServiceWorkerDevToolsAgentHost> host = it->second; + host->UpdateCrossOriginEmbedderPolicy( + std::move(cross_origin_embedder_policy)); +} + void ServiceWorkerDevToolsManager::WorkerVersionInstalled(int worker_process_id, int worker_route_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/content/browser/devtools/service_worker_devtools_manager.h b/content/browser/devtools/service_worker_devtools_manager.h index 83ac10a8..aab651b 100644 --- a/content/browser/devtools/service_worker_devtools_manager.h +++ b/content/browser/devtools/service_worker_devtools_manager.h
@@ -16,6 +16,7 @@ #include "base/observer_list.h" #include "base/unguessable_token.h" #include "content/common/content_export.h" +#include "services/network/public/cpp/cross_origin_embedder_policy.h" #include "services/network/public/mojom/url_response_head.mojom-forward.h" #include "third_party/blink/public/mojom/devtools/devtools_agent.mojom.h" #include "url/gurl.h" @@ -66,6 +67,8 @@ const GURL& url, const GURL& scope, bool is_installed_version, + base::Optional<network::CrossOriginEmbedderPolicy> + cross_origin_embedder_policy, base::UnguessableToken* devtools_worker_token, bool* pause_on_start); void WorkerReadyForInspection( @@ -73,6 +76,10 @@ int worker_route_id, mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote, mojo::PendingReceiver<blink::mojom::DevToolsAgentHost> host_receiver); + void UpdateCrossOriginEmbedderPolicy( + int worker_process_id, + int worker_route_id, + network::CrossOriginEmbedderPolicy cross_origin_embedder_policy); void WorkerVersionInstalled(int worker_process_id, int worker_route_id); void WorkerVersionDoomed(int worker_process_id, int worker_route_id); void WorkerDestroyed(int worker_process_id, int worker_route_id);
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc index a803a8b9..7b0c02d 100644 --- a/content/browser/frame_host/frame_tree.cc +++ b/content/browser/frame_host/frame_tree.cc
@@ -384,14 +384,12 @@ scoped_refptr<RenderViewHostImpl> FrameTree::CreateRenderViewHost( SiteInstance* site_instance, - int32_t routing_id, int32_t main_frame_routing_id, - int32_t widget_routing_id, bool swapped_out) { RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(RenderViewHostFactory::Create( site_instance, render_view_delegate_, render_widget_delegate_, - routing_id, main_frame_routing_id, widget_routing_id, swapped_out)); + main_frame_routing_id, swapped_out)); RegisterRenderViewHost(rvh); return base::WrapRefCounted(rvh); }
diff --git a/content/browser/frame_host/frame_tree.h b/content/browser/frame_host/frame_tree.h index f859e576..0b44b163 100644 --- a/content/browser/frame_host/frame_tree.h +++ b/content/browser/frame_host/frame_tree.h
@@ -207,9 +207,7 @@ // of this object. scoped_refptr<RenderViewHostImpl> CreateRenderViewHost( SiteInstance* site_instance, - int32_t routing_id, int32_t main_frame_routing_id, - int32_t widget_routing_id, bool swapped_out); // Returns the existing RenderViewHost for a new RenderFrameHost.
diff --git a/content/browser/frame_host/frame_tree_unittest.cc b/content/browser/frame_host/frame_tree_unittest.cc index 79c50ef..8b7b4ba 100644 --- a/content/browser/frame_host/frame_tree_unittest.cc +++ b/content/browser/frame_host/frame_tree_unittest.cc
@@ -166,7 +166,7 @@ // itself. Instead, leave them in "not live" state, which is indicated by the // * after the frame id, since this test cares about the shape, not the // frame liveness. - EXPECT_EQ("3: []", GetTreeState(frame_tree)); + EXPECT_EQ("1: []", GetTreeState(frame_tree)); constexpr auto kOwnerType = blink::FrameOwnerElementType::kIframe; // Simulate attaching a series of frames to build the frame tree. @@ -208,7 +208,7 @@ blink::mojom::FrameOwnerProperties(), false, kOwnerType); EXPECT_EQ( - "3: [14: [244: [], 245: []], " + "1: [14: [244: [], 245: []], " "15: [255 'no children node': []], " "16: []]", GetTreeState(frame_tree)); @@ -276,7 +276,7 @@ // Now that's it's fully built, verify the tree structure is as expected. EXPECT_EQ( - "3: [14: [244: [], 245: []], " + "1: [14: [244: [], 245: []], " "15: [255 'no children node': []], " "16: [264: [], 265: [], 266: [], " "267 'node with deep subtree': " @@ -290,27 +290,27 @@ FrameTreeNode* child_245 = child_14->child_at(1); FrameTreeNode* child_555 = child_267->child_at(0)->child_at(0)->child_at(0); FrameTreeNode* child_655 = child_555->child_at(0); - EXPECT_EQ("3 14 15 16 244 245 255 264 265 266 267 268 365 455 555 655", + EXPECT_EQ("1 14 15 16 244 245 255 264 265 266 267 268 365 455 555 655", GetTraversalOrder(frame_tree, nullptr)); - EXPECT_EQ("3", GetTraversalOrder(frame_tree, root)); - EXPECT_EQ("3 14 15 16 255 264 265 266 267 268 365 455 555 655", + EXPECT_EQ("1", GetTraversalOrder(frame_tree, root)); + EXPECT_EQ("1 14 15 16 255 264 265 266 267 268 365 455 555 655", GetTraversalOrder(frame_tree, child_14)); - EXPECT_EQ("3 14 15 16 244 245 255 264 265 266 267 268 365 455 555 655", + EXPECT_EQ("1 14 15 16 244 245 255 264 265 266 267 268 365 455 555 655", GetTraversalOrder(frame_tree, child_244)); - EXPECT_EQ("3 14 15 16 244 245 255 264 265 266 267 268 365 455 555 655", + EXPECT_EQ("1 14 15 16 244 245 255 264 265 266 267 268 365 455 555 655", GetTraversalOrder(frame_tree, child_245)); - EXPECT_EQ("3 14 15 16 244 245 264 265 266 267 268 365 455 555 655", + EXPECT_EQ("1 14 15 16 244 245 264 265 266 267 268 365 455 555 655", GetTraversalOrder(frame_tree, child_15)); - EXPECT_EQ("3 14 15 16 244 245 255 264 265 266 267 268", + EXPECT_EQ("1 14 15 16 244 245 255 264 265 266 267 268", GetTraversalOrder(frame_tree, child_267)); - EXPECT_EQ("3 14 15 16 244 245 255 264 265 266 267 268 365 455 555", + EXPECT_EQ("1 14 15 16 244 245 255 264 265 266 267 268 365 455 555", GetTraversalOrder(frame_tree, child_555)); - EXPECT_EQ("3 14 15 16 244 245 255 264 265 266 267 268 365 455 555 655", + EXPECT_EQ("1 14 15 16 244 245 255 264 265 266 267 268 365 455 555 655", GetTraversalOrder(frame_tree, child_655)); frame_tree->RemoveFrame(child_555); EXPECT_EQ( - "3: [14: [244: [], 245: []], " + "1: [14: [244: [], 245: []], " "15: [255 'no children node': []], " "16: [264: [], 265: [], 266: [], " "267 'node with deep subtree': " @@ -319,7 +319,7 @@ frame_tree->RemoveFrame(child_16->child_at(1)); EXPECT_EQ( - "3: [14: [244: [], 245: []], " + "1: [14: [244: [], 245: []], " "15: [255 'no children node': []], " "16: [264: [], 266: [], " "267 'node with deep subtree': " @@ -328,7 +328,7 @@ frame_tree->RemoveFrame(root->child_at(1)); EXPECT_EQ( - "3: [14: [244: [], 245: []], " + "1: [14: [244: [], 245: []], " "16: [264: [], 266: [], " "267 'node with deep subtree': " "[365: [455: []]], 268: []]]", @@ -460,7 +460,7 @@ TEST_F(FrameTreeTest, ObserverWalksTreeDuringFrameCreation) { TreeWalkingWebContentsLogger activity(contents()); contents()->NavigateAndCommit(GURL("http://www.google.com")); - EXPECT_EQ("RenderFrameCreated(3) -> 3: []", activity.GetLog()); + EXPECT_EQ("RenderFrameCreated(1) -> 1: []", activity.GetLog()); FrameTree* frame_tree = contents()->GetFrameTree(); FrameTreeNode* root = frame_tree->root(); @@ -474,8 +474,8 @@ base::UnguessableToken::Create(), blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType); EXPECT_EQ( - "RenderFrameHostChanged(new)(14) -> 3: []\n" - "RenderFrameCreated(14) -> 3: [14: []]", + "RenderFrameHostChanged(new)(14) -> 1: []\n" + "RenderFrameCreated(14) -> 1: [14: []]", activity.GetLog()); main_test_rfh()->OnCreateChildFrame( 18, CreateStubInterfaceProviderReceiver(), @@ -484,13 +484,13 @@ base::UnguessableToken::Create(), blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType); EXPECT_EQ( - "RenderFrameHostChanged(new)(18) -> 3: [14: []]\n" - "RenderFrameCreated(18) -> 3: [14: [], 18: []]", + "RenderFrameHostChanged(new)(18) -> 1: [14: []]\n" + "RenderFrameCreated(18) -> 1: [14: [], 18: []]", activity.GetLog()); frame_tree->RemoveFrame(root->child_at(0)); - EXPECT_EQ("RenderFrameDeleted(14) -> 3: [18: []]", activity.GetLog()); + EXPECT_EQ("RenderFrameDeleted(14) -> 1: [18: []]", activity.GetLog()); frame_tree->RemoveFrame(root->child_at(0)); - EXPECT_EQ("RenderFrameDeleted(18) -> 3: []", activity.GetLog()); + EXPECT_EQ("RenderFrameDeleted(18) -> 1: []", activity.GetLog()); } // Make sure that WebContentsObservers see a consistent view of the tree after @@ -498,7 +498,7 @@ TEST_F(FrameTreeTest, ObserverWalksTreeAfterCrash) { TreeWalkingWebContentsLogger activity(contents()); contents()->NavigateAndCommit(GURL("http://www.google.com")); - EXPECT_EQ("RenderFrameCreated(3) -> 3: []", activity.GetLog()); + EXPECT_EQ("RenderFrameCreated(1) -> 1: []", activity.GetLog()); constexpr auto kOwnerType = blink::FrameOwnerElementType::kIframe; main_test_rfh()->OnCreateChildFrame( @@ -508,8 +508,8 @@ base::UnguessableToken::Create(), blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType); EXPECT_EQ( - "RenderFrameHostChanged(new)(22) -> 3: []\n" - "RenderFrameCreated(22) -> 3: [22: []]", + "RenderFrameHostChanged(new)(22) -> 1: []\n" + "RenderFrameCreated(22) -> 1: [22: []]", activity.GetLog()); main_test_rfh()->OnCreateChildFrame( 23, CreateStubInterfaceProviderReceiver(), @@ -518,17 +518,17 @@ base::UnguessableToken::Create(), blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType); EXPECT_EQ( - "RenderFrameHostChanged(new)(23) -> 3: [22: []]\n" - "RenderFrameCreated(23) -> 3: [22: [], 23: []]", + "RenderFrameHostChanged(new)(23) -> 1: [22: []]\n" + "RenderFrameCreated(23) -> 1: [22: [], 23: []]", activity.GetLog()); // Crash the renderer main_test_rfh()->GetProcess()->SimulateCrash(); EXPECT_EQ( - "RenderProcessGone -> 3*: [22*: [], 23*: []]\n" - "RenderFrameDeleted(23) -> 3*: []\n" - "RenderFrameDeleted(22) -> 3*: []\n" - "RenderFrameDeleted(3) -> 3*: []", + "RenderProcessGone -> 1*: [22*: [], 23*: []]\n" + "RenderFrameDeleted(23) -> 1*: []\n" + "RenderFrameDeleted(22) -> 1*: []\n" + "RenderFrameDeleted(1) -> 1*: []", activity.GetLog()); } @@ -540,7 +540,7 @@ FrameTreeNode* root = frame_tree->root(); int process_id = root->current_frame_host()->GetProcess()->GetID(); - ASSERT_EQ("3: []", GetTreeState(frame_tree)); + ASSERT_EQ("1: []", GetTreeState(frame_tree)); // Simulate attaching a frame from mismatched process id. ASSERT_FALSE(frame_tree->AddFrame( @@ -550,7 +550,7 @@ base::UnguessableToken::Create(), blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false, blink::FrameOwnerElementType::kIframe)); - ASSERT_EQ("3: []", GetTreeState(frame_tree)); + ASSERT_EQ("1: []", GetTreeState(frame_tree)); } // Ensure that frames removed while a process has crashed are not preserved in
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc index c1bb496..09cec85 100644 --- a/content/browser/frame_host/interstitial_page_impl.cc +++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -602,9 +602,8 @@ SessionStorageNamespaceImpl::Create(dom_storage_context); // Use the RenderViewHost from our FrameTree. - frame_tree_->root()->render_manager()->Init( - site_instance.get(), MSG_ROUTING_NONE, MSG_ROUTING_NONE, MSG_ROUTING_NONE, - false); + frame_tree_->root()->render_manager()->Init(site_instance.get(), + MSG_ROUTING_NONE, false); return frame_tree_->root()->current_frame_host()->render_view_host(); }
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index 147bce2..9a394012 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -1821,30 +1821,45 @@ auto cross_origin_embedder_policy = response_head_->cross_origin_embedder_policy; if (base::FeatureList::IsEnabled(network::features::kCrossOriginIsolation)) { - // https://mikewest.github.io/corpp/#integration-html + // https://mikewest.github.io/corpp/#process-navigation-response if (auto* const parent_frame = GetParentFrame()) { const auto& parent_coep = parent_frame->cross_origin_embedder_policy(); const auto& url = common_params_->url; - if (parent_coep.value == - network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp) { - if (url.SchemeIsBlob() || url.SchemeIs(url::kDataScheme)) { - // Some special URLs not loaded using the network are inheriting the - // Cross-Origin-Embedder-Policy header from their parent. - cross_origin_embedder_policy.value = - network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp; + constexpr auto kRequireCorp = + network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp; + constexpr auto kNone = + network::mojom::CrossOriginEmbedderPolicyValue::kNone; + + // Some special URLs not loaded using the network are inheriting the + // Cross-Origin-Embedder-Policy header from their parent. + const bool has_allowed_scheme = + url.SchemeIsBlob() || url.SchemeIs(url::kDataScheme); + if (parent_coep.value == kRequireCorp && has_allowed_scheme) { + cross_origin_embedder_policy.value = kRequireCorp; + } + + auto* const coep_reporter = parent_frame->coep_reporter(); + if (parent_coep.report_only_value == kRequireCorp && + !has_allowed_scheme && cross_origin_embedder_policy.value == kNone && + coep_reporter) { + coep_reporter->QueueNavigationReport(redirect_chain_[0], + /*report_only=*/true); + } + if (parent_coep.value == kRequireCorp && + cross_origin_embedder_policy.value == kNone) { + if (coep_reporter) { + coep_reporter->QueueNavigationReport(redirect_chain_[0], + /*report_only=*/false); } - if (cross_origin_embedder_policy.value == - network::mojom::CrossOriginEmbedderPolicyValue::kNone) { - OnRequestFailedInternal(network::URLLoaderCompletionStatus( - network::BlockedByResponseReason:: - kCoepFrameResourceNeedsCoepHeader), - false /* skip_throttles */, - base::nullopt /* error_page_content */, - false /* collapse_frame */); - // DO NOT ADD CODE after this. The previous call to - // OnRequestFailedInternal has destroyed the NavigationRequest. - return; - } + OnRequestFailedInternal(network::URLLoaderCompletionStatus( + network::BlockedByResponseReason:: + kCoepFrameResourceNeedsCoepHeader), + false /* skip_throttles */, + base::nullopt /* error_page_content */, + false /* collapse_frame */); + // DO NOT ADD CODE after this. The previous call to + // OnRequestFailedInternal has destroyed the NavigationRequest. + return; } }
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 0d33a622..362d1b0 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2297,9 +2297,7 @@ // Initialize the RenderFrameHost for the new node. We always create child // frames in the same SiteInstance as the current frame, and they can swap to // a different one if they navigate away. - child->render_manager()->Init(GetSiteInstance(), - render_view_host()->GetRoutingID(), - frame_routing_id, MSG_ROUTING_NONE, false); + child->render_manager()->Init(GetSiteInstance(), frame_routing_id, false); // Other renderer processes in this BrowsingInstance may need to find out // about the new frame. Create a proxy for the child frame in all
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc index 88e0657..d9e3b753 100644 --- a/content/browser/frame_host/render_frame_host_manager.cc +++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -285,13 +285,10 @@ } void RenderFrameHostManager::Init(SiteInstance* site_instance, - int32_t view_routing_id, int32_t frame_routing_id, - int32_t widget_routing_id, bool renderer_initiated_creation) { DCHECK(site_instance); - SetRenderFrameHost(CreateRenderFrameHost(site_instance, view_routing_id, - frame_routing_id, widget_routing_id, + SetRenderFrameHost(CreateRenderFrameHost(site_instance, frame_routing_id, renderer_initiated_creation)); // Notify the delegate of the creation of the current RenderFrameHost. @@ -2044,9 +2041,7 @@ std::unique_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost( SiteInstance* site_instance, - int32_t view_routing_id, int32_t frame_routing_id, - int32_t widget_routing_id, bool renderer_initiated_creation) { if (frame_routing_id == MSG_ROUTING_NONE) frame_routing_id = site_instance->GetProcess()->GetNextRoutingID(); @@ -2058,24 +2053,9 @@ if (frame_tree_node_->IsMainFrame()) { if (!render_view_host) { - render_view_host = frame_tree->CreateRenderViewHost( - site_instance, view_routing_id, frame_routing_id, widget_routing_id, - /*swapped_out=*/false); - } - // TODO(avi): It's a bit bizarre that this logic lives here instead of in - // CreateRenderFrame(). It turns out that FrameTree::CreateRenderViewHost - // doesn't /always/ create a new RenderViewHost. It first tries to find an - // already existing one to reuse by a SiteInstance lookup. If it finds one, - // then the supplied routing IDs are completely ignored. - // CreateRenderFrame() could do this lookup too, but it seems redundant to - // do this lookup in two places. This is a good yak shave to clean up, or, - // if just ignored, should be an easy cleanup once RenderViewHostImpl has-a - // RenderWidgetHostImpl. https://crbug.com/545684 - if (view_routing_id == MSG_ROUTING_NONE) { - widget_routing_id = render_view_host->GetWidget()->GetRoutingID(); - } else { - DCHECK_NE(view_routing_id, widget_routing_id); - DCHECK_EQ(view_routing_id, render_view_host->GetRoutingID()); + render_view_host = + frame_tree->CreateRenderViewHost(site_instance, frame_routing_id, + /*swapped_out=*/false); } } CHECK(render_view_host); @@ -2144,8 +2124,8 @@ render_frame_host_->must_be_replaced() || IsRenderDocumentEnabled()); std::unique_ptr<RenderFrameHostImpl> new_render_frame_host = - CreateRenderFrameHost(instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, - MSG_ROUTING_NONE, false); + CreateRenderFrameHost(instance, MSG_ROUTING_NONE, + /*renderer_initiated_creation=*/false); DCHECK_EQ(new_render_frame_host->GetSiteInstance(), instance); // Prevent the process from exiting while we're trying to navigate in it. @@ -2236,7 +2216,7 @@ // Before creating a new RenderFrameProxyHost, ensure a RenderViewHost // exists for |instance|, as it creates the page level structure in Blink. render_view_host = frame_tree_node_->frame_tree()->CreateRenderViewHost( - instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, MSG_ROUTING_NONE, + instance, /*frame_routing_id=*/MSG_ROUTING_NONE, /*swapped_out=*/true); } proxy = CreateRenderFrameProxyHost(instance, std::move(render_view_host));
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h index 8741164..1a49e27 100644 --- a/content/browser/frame_host/render_frame_host_manager.h +++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -183,9 +183,7 @@ // For arguments, see WebContentsImpl constructor. void Init(SiteInstance* site_instance, - int32_t view_routing_id, int32_t frame_routing_id, - int32_t widget_routing_id, bool renderer_initiated_creation); // Returns the currently active RenderFrameHost. @@ -695,9 +693,7 @@ // Creates a RenderFrameHost and corresponding RenderViewHost if necessary. std::unique_ptr<RenderFrameHostImpl> CreateRenderFrameHost( SiteInstance* instance, - int32_t view_routing_id, int32_t frame_routing_id, - int32_t widget_routing_id, bool renderer_initiated_creation); // Create and initialize a speculative RenderFrameHost for an ongoing
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc index 0d2a062..59c25e44 100644 --- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc +++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -23,6 +23,8 @@ #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/synchronization/waitable_event.h" +#include "base/synchronization/waitable_event_watcher.h" #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/test/bind_test_util.h" @@ -361,15 +363,29 @@ base::RunLoop loop; IndexedDBOriginState* per_origin_factory = factory->GetOriginFactory(origin); - per_origin_factory->backing_store() - ->db() - ->leveldb_state() - ->RequestDestruction(loop.QuitClosure(), - base::SequencedTaskRunnerHandle::Get()); + + auto* leveldb_state = + per_origin_factory->backing_store()->db()->leveldb_state(); + + base::WaitableEvent leveldb_close_event; + base::WaitableEventWatcher event_watcher; + leveldb_state->RequestDestruction(&leveldb_close_event); + event_watcher.StartWatching( + &leveldb_close_event, + base::BindLambdaForTesting( + [&](base::WaitableEvent*) { loop.Quit(); }), + base::SequencedTaskRunnerHandle::Get()); + idb_context_->ForceCloseSync( origin, storage::mojom::ForceCloseReason::FORCE_CLOSE_DELETE_ORIGIN); loop.Run(); + // There is a possible race in |leveldb_close_event| where the signaling + // thread is still in the WaitableEvent::Signal() method. To ensure that + // the other thread exits their Signal method, any method on the + // WaitableEvent can be called to acquire the internal lock (which will + // subsequently wait for the other thread to exit the Signal method). + EXPECT_TRUE(leveldb_close_event.IsSignaled()); } // All leveldb databases are closed, and they can be deleted. for (auto origin : idb_context_->GetAllOrigins()) {
diff --git a/content/browser/indexed_db/indexed_db_factory_impl.cc b/content/browser/indexed_db/indexed_db_factory_impl.cc index 7d3ae3ed..017d721 100644 --- a/content/browser/indexed_db/indexed_db_factory_impl.cc +++ b/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -769,7 +769,7 @@ // Scopes must be single sequence to keep methods like ForceClose synchronous. // See https://crbug.com/980685 s = backing_store->db()->scopes()->StartRecoveryAndCleanupTasks( - LevelDBScopes::TaskRunnerMode::kUseCurrentSequence); + LevelDBScopes::TaskRunnerMode::kNewCleanupAndRevertSequences); if (UNLIKELY(!s.ok())) { ReportOpenStatus(indexed_db::INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY,
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc index 301a9f4..33e50e4 100644 --- a/content/browser/indexed_db/indexed_db_factory_unittest.cc +++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -90,32 +90,18 @@ // deletion of the leveldb state. Once the states are no longer around, // delete all of the databases on disk. auto open_factory_origins = factory->GetOpenOrigins(); - base::RunLoop loop; - auto callback = base::BarrierClosure( - open_factory_origins.size(), base::BindLambdaForTesting([&]() { - // All leveldb databases are closed, and they can be deleted. - for (auto origin : context_->GetAllOrigins()) { - bool success = false; - storage::mojom::IndexedDBControlAsyncWaiter waiter( - context_.get()); - waiter.DeleteForOrigin(origin, &success); - EXPECT_TRUE(success); - } - loop.Quit(); - })); for (auto origin : open_factory_origins) { - IndexedDBOriginState* per_origin_factory = - factory->GetOriginFactory(origin); - per_origin_factory->backing_store() - ->db() - ->leveldb_state() - ->RequestDestruction(callback, - base::SequencedTaskRunnerHandle::Get()); context_->ForceCloseSync( origin, storage::mojom::ForceCloseReason::FORCE_CLOSE_DELETE_ORIGIN); } - loop.Run(); + // All leveldb databases are closed, and they can be deleted. + for (auto origin : context_->GetAllOrigins()) { + bool success = false; + storage::mojom::IndexedDBControlAsyncWaiter waiter(context_.get()); + waiter.DeleteForOrigin(origin, &success); + EXPECT_TRUE(success); + } } if (temp_dir_.IsValid()) ASSERT_TRUE(temp_dir_.Delete());
diff --git a/content/browser/indexed_db/indexed_db_origin_state.cc b/content/browser/indexed_db/indexed_db_origin_state.cc index 2bd391c..4f63b3f 100644 --- a/content/browser/indexed_db/indexed_db_origin_state.cc +++ b/content/browser/indexed_db/indexed_db_origin_state.cc
@@ -13,6 +13,7 @@ #include "base/feature_list.h" #include "base/rand_util.h" #include "base/stl_util.h" +#include "base/synchronization/waitable_event.h" #include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.h" #include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_factory.h" #include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction.h" @@ -109,8 +110,16 @@ IndexedDBOriginState::~IndexedDBOriginState() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (backing_store_ && backing_store_->IsBlobCleanupPending()) + if (!backing_store_) + return; + if (backing_store_->IsBlobCleanupPending()) backing_store_->ForceRunBlobCleanup(); + + base::WaitableEvent leveldb_destruct_event; + backing_store_->db()->leveldb_state()->RequestDestruction( + &leveldb_destruct_event); + backing_store_.reset(); + leveldb_destruct_event.Wait(); } void IndexedDBOriginState::AbortAllTransactions(bool compact) {
diff --git a/content/browser/indexed_db/indexed_db_origin_state.h b/content/browser/indexed_db/indexed_db_origin_state.h index b2a6cc9..5aba88ea 100644 --- a/content/browser/indexed_db/indexed_db_origin_state.h +++ b/content/browser/indexed_db/indexed_db_origin_state.h
@@ -213,7 +213,7 @@ ClosingState closing_stage_ = ClosingState::kNotClosing; base::OneShotTimer close_timer_; const std::unique_ptr<DisjointRangeLockManager> lock_manager_; - const std::unique_ptr<IndexedDBBackingStore> backing_store_; + std::unique_ptr<IndexedDBBackingStore> backing_store_; OriginDBMap databases_; // This is the refcount for the number of IndexedDBOriginStateHandle's given
diff --git a/content/browser/indexed_db/indexed_db_unittest.cc b/content/browser/indexed_db/indexed_db_unittest.cc index 1a08961..f3666863 100644 --- a/content/browser/indexed_db/indexed_db_unittest.cc +++ b/content/browser/indexed_db/indexed_db_unittest.cc
@@ -119,33 +119,20 @@ // deletion of the leveldb state. Once the states are no longer around, // delete all of the databases on disk. auto open_factory_origins = factory->GetOpenOrigins(); - base::RunLoop loop; - auto callback = base::BarrierClosure( - open_factory_origins.size(), base::BindLambdaForTesting([&]() { - // All leveldb databases are closed, and they can be deleted. - for (auto origin : context_->GetAllOrigins()) { - bool success = false; - storage::mojom::IndexedDBControlAsyncWaiter waiter( - context_.get()); - waiter.DeleteForOrigin(origin, &success); - EXPECT_TRUE(success); - } - loop.Quit(); - })); for (auto origin : open_factory_origins) { - IndexedDBOriginState* per_origin_factory = - factory->GetOriginFactory(origin); - per_origin_factory->backing_store() - ->db() - ->leveldb_state() - ->RequestDestruction(callback, - base::SequencedTaskRunnerHandle::Get()); context_->ForceCloseSync( origin, storage::mojom::ForceCloseReason::FORCE_CLOSE_DELETE_ORIGIN); } - loop.Run(); + // All leveldb databases are closed, and they can be deleted. + for (auto origin : context_->GetAllOrigins()) { + bool success = false; + storage::mojom::IndexedDBControlAsyncWaiter waiter(context_.get()); + waiter.DeleteForOrigin(origin, &success); + EXPECT_TRUE(success); + } } + if (temp_dir_.IsValid()) ASSERT_TRUE(temp_dir_.Delete()); }
diff --git a/content/browser/net/cross_origin_embedder_policy_reporter.cc b/content/browser/net/cross_origin_embedder_policy_reporter.cc index e0a7c58..b435f1c 100644 --- a/content/browser/net/cross_origin_embedder_policy_reporter.cc +++ b/content/browser/net/cross_origin_embedder_policy_reporter.cc
@@ -45,6 +45,26 @@ std::move(body)); } +void CrossOriginEmbedderPolicyReporter::QueueNavigationReport( + const GURL& blocked_url, + bool report_only) { + const base::Optional<std::string>& endpoint = + report_only ? report_only_endpoint_ : endpoint_; + if (!endpoint) { + return; + } + url::Replacements<char> replacements; + replacements.ClearUsername(); + replacements.ClearPassword(); + base::DictionaryValue body; + body.SetString("type", "navigation"); + body.SetString("blocked-url", + blocked_url.ReplaceComponents(replacements).spec()); + storage_partition_->GetNetworkContext()->QueueReport( + "coep", *endpoint, context_url_, /*user_agent=*/base::nullopt, + std::move(body)); +} + void CrossOriginEmbedderPolicyReporter::Clone( mojo::PendingReceiver<network::mojom::CrossOriginEmbedderPolicyReporter> receiver) {
diff --git a/content/browser/net/cross_origin_embedder_policy_reporter.h b/content/browser/net/cross_origin_embedder_policy_reporter.h index 7317460..4aa4f06 100644 --- a/content/browser/net/cross_origin_embedder_policy_reporter.h +++ b/content/browser/net/cross_origin_embedder_policy_reporter.h
@@ -48,6 +48,10 @@ mojo::PendingReceiver<network::mojom::CrossOriginEmbedderPolicyReporter> receiver) override; + // https://mikewest.github.io/corpp/#abstract-opdef-queue-coep-navigation-violation + // Queue a violation report for COEP mismatch for nested frame navigation. + void QueueNavigationReport(const GURL& blocked_url, bool report_only); + private: // See the class comment. StoragePartition* const storage_partition_;
diff --git a/content/browser/net/cross_origin_embedder_policy_reporter_unittest.cc b/content/browser/net/cross_origin_embedder_policy_reporter_unittest.cc index 8cd8411..93a2043f 100644 --- a/content/browser/net/cross_origin_embedder_policy_reporter_unittest.cc +++ b/content/browser/net/cross_origin_embedder_policy_reporter_unittest.cc
@@ -10,12 +10,15 @@ #include "base/values.h" #include "content/public/test/test_storage_partition.h" #include "mojo/public/cpp/bindings/remote.h" +#include "services/network/public/cpp/cross_origin_embedder_policy.h" #include "services/network/test/test_network_context.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { namespace { +using network::CrossOriginEmbedderPolicy; + class TestNetworkContext : public network::TestNetworkContext { public: struct Report { @@ -55,20 +58,27 @@ StoragePartition* storage_partition() { return &storage_partition_; } const TestNetworkContext& network_context() const { return network_context_; } - base::Value CreateBody(base::StringPiece s) { + base::Value CreateBodyForCorp(base::StringPiece s) { base::Value dict(base::Value::Type::DICTIONARY); dict.SetKey("type", base::Value("corp")); dict.SetKey("blocked-url", base::Value(s)); return dict; } + base::Value CreateBodyForNavigation(base::StringPiece s) { + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetKey("type", base::Value("navigation")); + dict.SetKey("blocked-url", base::Value(s)); + return dict; + } + private: base::test::TaskEnvironment task_environment_; TestNetworkContext network_context_; TestStoragePartition storage_partition_; }; -TEST_F(CrossOriginEmbedderPolicyReporterTest, NullEndpoints) { +TEST_F(CrossOriginEmbedderPolicyReporterTest, NullEndpointsForCorp) { const GURL kContextUrl("https://example.com/path"); CrossOriginEmbedderPolicyReporter reporter(storage_partition(), kContextUrl, base::nullopt, base::nullopt); @@ -81,7 +91,7 @@ EXPECT_TRUE(network_context().reports().empty()); } -TEST_F(CrossOriginEmbedderPolicyReporterTest, Basic) { +TEST_F(CrossOriginEmbedderPolicyReporterTest, BasicCorp) { const GURL kContextUrl("https://example.com/path"); CrossOriginEmbedderPolicyReporter reporter(storage_partition(), kContextUrl, "e1", "e2"); @@ -99,14 +109,15 @@ EXPECT_EQ(r1.type, "coep"); EXPECT_EQ(r1.group, "e1"); EXPECT_EQ(r1.url, kContextUrl); - EXPECT_EQ(r1.body, CreateBody("https://www1.example.com/x#foo?bar=baz")); + EXPECT_EQ(r1.body, + CreateBodyForCorp("https://www1.example.com/x#foo?bar=baz")); EXPECT_EQ(r2.type, "coep"); EXPECT_EQ(r2.group, "e2"); EXPECT_EQ(r2.url, kContextUrl); - EXPECT_EQ(r2.body, CreateBody("http://www2.example.com:41/y")); + EXPECT_EQ(r2.body, CreateBodyForCorp("http://www2.example.com:41/y")); } -TEST_F(CrossOriginEmbedderPolicyReporterTest, UserAndPass) { +TEST_F(CrossOriginEmbedderPolicyReporterTest, UserAndPassForCorp) { const GURL kContextUrl("https://example.com/path"); CrossOriginEmbedderPolicyReporter reporter(storage_partition(), kContextUrl, "e1", "e2"); @@ -123,11 +134,11 @@ EXPECT_EQ(r1.type, "coep"); EXPECT_EQ(r1.group, "e1"); EXPECT_EQ(r1.url, kContextUrl); - EXPECT_EQ(r1.body, CreateBody("https://www1.example.com/x")); + EXPECT_EQ(r1.body, CreateBodyForCorp("https://www1.example.com/x")); EXPECT_EQ(r2.type, "coep"); EXPECT_EQ(r2.group, "e2"); EXPECT_EQ(r2.url, kContextUrl); - EXPECT_EQ(r2.body, CreateBody("https://www2.example.com/y")); + EXPECT_EQ(r2.body, CreateBodyForCorp("https://www2.example.com/y")); } TEST_F(CrossOriginEmbedderPolicyReporterTest, Clone) { @@ -152,11 +163,75 @@ EXPECT_EQ(r1.type, "coep"); EXPECT_EQ(r1.group, "e1"); EXPECT_EQ(r1.url, kContextUrl); - EXPECT_EQ(r1.body, CreateBody("https://www1.example.com/x")); + EXPECT_EQ(r1.body, CreateBodyForCorp("https://www1.example.com/x")); EXPECT_EQ(r2.type, "coep"); EXPECT_EQ(r2.group, "e2"); EXPECT_EQ(r2.url, kContextUrl); - EXPECT_EQ(r2.body, CreateBody("https://www2.example.com/y")); + EXPECT_EQ(r2.body, CreateBodyForCorp("https://www2.example.com/y")); +} + +TEST_F(CrossOriginEmbedderPolicyReporterTest, NullEndpointsForNavigation) { + const GURL kContextUrl("https://example.com/path"); + CrossOriginEmbedderPolicyReporter reporter(storage_partition(), kContextUrl, + base::nullopt, base::nullopt); + + reporter.QueueNavigationReport(GURL("https://www1.example.com/y"), + /*report_only=*/false); + reporter.QueueNavigationReport(GURL("https://www2.example.com/x"), + /*report_only=*/true); + + EXPECT_TRUE(network_context().reports().empty()); +} + +TEST_F(CrossOriginEmbedderPolicyReporterTest, BasicNavigation) { + const GURL kContextUrl("https://example.com/path"); + CrossOriginEmbedderPolicyReporter reporter(storage_partition(), kContextUrl, + "e1", "e2"); + CrossOriginEmbedderPolicy child_coep; + child_coep.report_only_value = + network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp; + + reporter.QueueNavigationReport(GURL("https://www1.example.com/x#foo?bar=baz"), + /*report_only=*/false); + reporter.QueueNavigationReport(GURL("http://www2.example.com:41/y"), + /*report_only=*/true); + + ASSERT_EQ(2u, network_context().reports().size()); + const Report& r1 = network_context().reports()[0]; + const Report& r2 = network_context().reports()[1]; + + EXPECT_EQ(r1.type, "coep"); + EXPECT_EQ(r1.group, "e1"); + EXPECT_EQ(r1.url, kContextUrl); + EXPECT_EQ(r1.body, + CreateBodyForNavigation("https://www1.example.com/x#foo?bar=baz")); + EXPECT_EQ(r2.type, "coep"); + EXPECT_EQ(r2.group, "e2"); + EXPECT_EQ(r2.url, kContextUrl); + EXPECT_EQ(r2.body, CreateBodyForNavigation("http://www2.example.com:41/y")); +} + +TEST_F(CrossOriginEmbedderPolicyReporterTest, UserAndPassForNavigation) { + const GURL kContextUrl("https://example.com/path"); + CrossOriginEmbedderPolicyReporter reporter(storage_partition(), kContextUrl, + "e1", "e2"); + reporter.QueueNavigationReport(GURL("https://u:p@www1.example.com/x"), + /*report_only=*/false); + reporter.QueueNavigationReport(GURL("https://u:p@www2.example.com/y"), + /*report_only=*/true); + + ASSERT_EQ(2u, network_context().reports().size()); + const Report& r1 = network_context().reports()[0]; + const Report& r2 = network_context().reports()[1]; + + EXPECT_EQ(r1.type, "coep"); + EXPECT_EQ(r1.group, "e1"); + EXPECT_EQ(r1.url, kContextUrl); + EXPECT_EQ(r1.body, CreateBodyForNavigation("https://www1.example.com/x")); + EXPECT_EQ(r2.type, "coep"); + EXPECT_EQ(r2.group, "e2"); + EXPECT_EQ(r2.url, kContextUrl); + EXPECT_EQ(r2.body, CreateBodyForNavigation("https://www2.example.com/y")); } } // namespace
diff --git a/content/browser/renderer_host/frame_connector_delegate.cc b/content/browser/renderer_host/frame_connector_delegate.cc index 4a2eb5d..29fb3387 100644 --- a/content/browser/renderer_host/frame_connector_delegate.cc +++ b/content/browser/renderer_host/frame_connector_delegate.cc
@@ -45,10 +45,10 @@ render_widget_host->SetAutoResize(visual_properties.auto_resize_enabled, visual_properties.min_size_for_auto_resize, visual_properties.max_size_for_auto_resize); - render_widget_host->SetPageScaleState( + render_widget_host->SetVisualPropertiesFromParentFrame( visual_properties.page_scale_factor, - visual_properties.is_pinch_gesture_active); - render_widget_host->SetCompositorViewport( + visual_properties.is_pinch_gesture_active, + visual_properties.visible_viewport_size, visual_properties.compositor_viewport); render_widget_host->SynchronizeVisualProperties();
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index c725561..ceb94cf 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -19,7 +19,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h" -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/command_line.h" #include "base/containers/adapters.h" #include "base/debug/alias.h" @@ -293,8 +293,8 @@ #include "services/service_manager/zygote/common/zygote_handle.h" // nogncheck #endif -#if BUILDFLAG(CLANG_COVERAGE_INSIDE_SANDBOX) -#include "content/common/coverage_utils.h" +#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) +#include "content/common/profiling_utils.h" #endif namespace content { @@ -3580,8 +3580,8 @@ child_process_->SetIPCLoggingEnabled(IPC::Logging::GetInstance()->Enabled()); #endif -#if BUILDFLAG(CLANG_COVERAGE_INSIDE_SANDBOX) - child_process_->SetCoverageFile(OpenCoverageFile()); +#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) + child_process_->SetProfilingFile(OpenProfilingFile()); #endif }
diff --git a/content/browser/renderer_host/render_view_host_factory.cc b/content/browser/renderer_host/render_view_host_factory.cc index b92cc3c4..f7e65761 100644 --- a/content/browser/renderer_host/render_view_host_factory.cc +++ b/content/browser/renderer_host/render_view_host_factory.cc
@@ -25,27 +25,10 @@ SiteInstance* instance, RenderViewHostDelegate* delegate, RenderWidgetHostDelegate* widget_delegate, - int32_t routing_id, int32_t main_frame_routing_id, - int32_t widget_routing_id, bool swapped_out) { - // RenderViewHost creation can be either browser-driven (by the user opening a - // new tab) or renderer-driven (by script calling window.open, etc). - // - // In the browser-driven case, the routing ID of the view is lazily assigned: - // this is signified by passing MSG_ROUTING_NONE for |routing_id|. - if (routing_id == MSG_ROUTING_NONE) { - DCHECK_EQ(widget_routing_id, MSG_ROUTING_NONE); - routing_id = instance->GetProcess()->GetNextRoutingID(); - widget_routing_id = instance->GetProcess()->GetNextRoutingID(); - } else { - // Otherwise, in the renderer-driven case, the routing ID of the view is - // already set. This is due to the fact that a sync render->browser IPC is - // involved. In order to quickly reply to the sync IPC, the routing IDs are - // assigned as early as possible. The IO thread immediately sends a reply to - // the sync IPC, while deferring the creation of the actual Host objects to - // the UI thread. - } + int32_t routing_id = instance->GetProcess()->GetNextRoutingID(); + int32_t widget_routing_id = instance->GetProcess()->GetNextRoutingID(); if (factory_) { return factory_->CreateRenderViewHost(instance, delegate, widget_delegate, routing_id, main_frame_routing_id,
diff --git a/content/browser/renderer_host/render_view_host_factory.h b/content/browser/renderer_host/render_view_host_factory.h index 6098562c..862f96e 100644 --- a/content/browser/renderer_host/render_view_host_factory.h +++ b/content/browser/renderer_host/render_view_host_factory.h
@@ -27,9 +27,7 @@ static RenderViewHost* Create(SiteInstance* instance, RenderViewHostDelegate* delegate, RenderWidgetHostDelegate* widget_delegate, - int32_t routing_id, int32_t main_frame_routing_id, - int32_t widget_routing_id, bool swapped_out); // Returns true if there is currently a globally-registered factory.
diff --git a/content/browser/renderer_host/render_widget_host_delegate.cc b/content/browser/renderer_host/render_widget_host_delegate.cc index 1118824..62bd672 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.cc +++ b/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -146,10 +146,6 @@ return ukm::kInvalidSourceId; } -gfx::Size RenderWidgetHostDelegate::GetAutoResizeSize() { - return gfx::Size(); -} - WebContents* RenderWidgetHostDelegate::GetAsWebContents() { return nullptr; }
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h index 3250e910..234baae 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.h +++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -313,20 +313,9 @@ // not a WebContents, returns nullptr. virtual WebContents* GetAsWebContents(); - // Gets the size set by a top-level frame with auto-resize enabled. - virtual gfx::Size GetAutoResizeSize(); - - // Reset the auto-size value, to indicate that auto-size is no longer active. - virtual void ResetAutoResizeSize() {} - // Returns true if there is context menu shown on page. virtual bool IsShowingContextMenuOnPage() const; - // Notifies all renderers in a page about changes to the size of the visible - // viewport. - virtual void NotifyVisibleViewportSizeChanged( - const gfx::Size& visible_viewport_size) {} - // Returns the focused frame across all delegates, or nullptr if none. virtual RenderFrameHostImpl* GetFocusedFrameFromFocusedDelegate();
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 51d09ae..40b9e63 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -779,21 +779,86 @@ visual_properties.min_size_for_auto_resize = min_size_for_auto_resize_; visual_properties.max_size_for_auto_resize = max_size_for_auto_resize_; - visual_properties.page_scale_factor = page_scale_factor_; - visual_properties.is_pinch_gesture_active = is_pinch_gesture_active_; - visual_properties.new_size = view_->GetRequestedRendererSize(); + + // This widget is for a frame that is the main frame of the outermost frame + // tree. That makes it the top-most frame. OR this is a non-frame widget. + const bool is_top_most_widget = !view_->IsRenderWidgetHostViewChildFrame(); + // This widget is for a frame, but not the main frame of its frame tree. + const bool is_child_frame_widget = + view_->IsRenderWidgetHostViewChildFrame() && !owner_delegate_; + + // These properties come from the main frame RenderWidget and flow down the + // tree of RenderWidgets. Some properties are global across all nested + // WebContents/frame trees. Some properties are global only within their + // WebContents/frame tree. + // + // Each child frame RenderWidgetHost that inherits values gets them from their + // parent RenderWidget in the renderer process. It then passes them along to + // its own RenderWidget, and the process repeats down the tree. + // + // The plumbing goes: + // 1. Browser: parent RenderWidgetHost + // 2. IPC -> WidgetMsg_UpdateVisualProperties + // 3. Renderer A: parent RenderWidget + // (sometimes blink involved) + // 4. Renderer A: child RenderFrameProxy + // 5. IPC -> FrameHostMsg_SynchronizeVisualProperties + // 6. Browser: child CrossProcessFrameConnector + // 7. Browser: parent RenderWidgetHost (We're here if |is_child_frame|.) + // 8. IPC -> WidgetMsg_UpdateVisualProperties + // 9. Renderer B: child RenderWidget + + // This property comes from the top-level main frame. + if (is_top_most_widget) { + visual_properties.compositor_viewport_pixel_rect = + gfx::Rect(view_->GetCompositorViewportPixelSize()); + } else { + visual_properties.compositor_viewport_pixel_rect = + properties_from_parent_local_root_.compositor_viewport; + if (!IsUseZoomForDSFEnabled()) { + // If UseZoomForDSF is not used, the coordinates were not scaled by DSF + // when coming from the renderer. + visual_properties.compositor_viewport_pixel_rect = + gfx::ScaleToEnclosingRect( + visual_properties.compositor_viewport_pixel_rect, + visual_properties.screen_info.device_scale_factor); + } + } + + // These properties come from the top-level main frame's renderer. The + // top-level main frame in the browser doesn't specify a value. + if (!is_top_most_widget) { + visual_properties.page_scale_factor = + properties_from_parent_local_root_.page_scale_factor; + visual_properties.is_pinch_gesture_active = + properties_from_parent_local_root_.is_pinch_gesture_active; + } + + // The |visible_viewport_size| is affected by auto-resize which is magical and + // tricky. + // + // For the top-level main frame, auto resize ends up asynchronously resizing + // the widget's RenderWidgetHostView and the size will show up there, so + // nothing needs to be written in here. + // + // For nested main frames, auto resize happens in the renderer so we need to + // store the size on this class and use that. When auto-resize is not enabled + // we use the size of the nested main frame's RenderWidgetHostView. + // + // For child frames, we always use the value provided from the parent. + // + // For non-frame widgets, there is no auto-resize and we behave like the top- + // level main frame. + gfx::Size viewport; + if (is_child_frame_widget) + viewport = properties_from_parent_local_root_.visible_viewport_size; + else + viewport = view_->GetVisibleViewportSize(); + visual_properties.visible_viewport_size = viewport; + visual_properties.capture_sequence_number = view_->GetCaptureSequenceNumber(); - // For OOPIFs, use the compositor viewport received from the FrameConnector. - visual_properties.compositor_viewport_pixel_rect = - view_->IsRenderWidgetHostViewChildFrame() - ? gfx::ScaleToEnclosingRect( - compositor_viewport_, - IsUseZoomForDSFEnabled() - ? 1.f - : visual_properties.screen_info.device_scale_factor) - : gfx::Rect(view_->GetCompositorViewportPixelSize()); - visual_properties.visible_viewport_size = view_->GetVisibleViewportSize(); + // TODO(ccameron): GetLocalSurfaceId is not synchronized with the device // scale factor of the surface. Fix this. viz::LocalSurfaceIdAllocation local_surface_id_allocation = @@ -869,22 +934,8 @@ visual_properties->scroll_focused_node_into_view = scroll_focused_node_into_view; - bool visible_viewport_size_changed = - !old_visual_properties_ || - old_visual_properties_->visible_viewport_size != - visual_properties->visible_viewport_size; - Send(new WidgetMsg_UpdateVisualProperties(routing_id_, *visual_properties)); - // TODO(danakj): All visual properties should go through - // WidgetMsg_UpdateVisualProperties in order to be synchronized by the - // LocalSurfaceIdAllocation which synchronizes in the display compositor for - // a global atomic screen update across all frame widgets. This should move. - if (delegate() && visible_viewport_size_changed) { - delegate()->NotifyVisibleViewportSizeChanged( - visual_properties->visible_viewport_size); - } - bool width_changed = !old_visual_properties_ || old_visual_properties_->new_size.width() != visual_properties->new_size.width(); @@ -1984,6 +2035,19 @@ return view_ ? view_->IsMouseLocked() : false; } +void RenderWidgetHostImpl::SetVisualPropertiesFromParentFrame( + float page_scale_factor, + bool is_pinch_gesture_active, + const gfx::Size& visible_viewport_size, + const gfx::Rect& compositor_viewport) { + properties_from_parent_local_root_.page_scale_factor = page_scale_factor; + properties_from_parent_local_root_.is_pinch_gesture_active = + is_pinch_gesture_active; + properties_from_parent_local_root_.visible_viewport_size = + visible_viewport_size; + properties_from_parent_local_root_.compositor_viewport = compositor_viewport; +} + void RenderWidgetHostImpl::SetAutoResize(bool enable, const gfx::Size& min_size, const gfx::Size& max_size) { @@ -1992,17 +2056,6 @@ max_size_for_auto_resize_ = max_size; } -void RenderWidgetHostImpl::SetPageScaleState(float page_scale_factor, - bool is_pinch_gesture_active) { - page_scale_factor_ = page_scale_factor; - is_pinch_gesture_active_ = is_pinch_gesture_active; -} - -void RenderWidgetHostImpl::SetCompositorViewport( - const gfx::Rect& compositor_viewport) { - compositor_viewport_ = compositor_viewport; -} - void RenderWidgetHostImpl::Destroy(bool also_delete) { DCHECK(!destroyed_); destroyed_ = true;
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 5c9ddfc..b6f95fd 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -581,8 +581,20 @@ renderer_initialized_ = renderer_initialized; } + // Store values received in a child frame RenderWidgetHost from a parent + // RenderWidget, in order to pass them to the renderer and continue their + // propagation down the RenderWidget tree. + void SetVisualPropertiesFromParentFrame( + float page_scale_factor, + bool is_pinch_gesture_active, + const gfx::Size& visible_viewport_size, + const gfx::Rect& compositor_viewport); + // Indicates if the render widget host should track the render widget's size // as opposed to visa versa. + // In main frame RenderWidgetHosts this controls the value for the frame tree. + // In child frame RenderWidgetHosts this value comes from the parent + // RenderWidget and should be propagated down the RenderWidgetTree. void SetAutoResize(bool enable, const gfx::Size& min_size, const gfx::Size& max_size); @@ -748,12 +760,6 @@ // Add/ClearPendingUserActivation() for details. bool RemovePendingUserActivationIfAvailable(); - // Allows the main frame's page scale state to be tracked. - void SetPageScaleState(float page_scale_factor, bool is_pinch_gesture_active); - - // Tracks the compositor viewport requested for an OOPIF subframe. - void SetCompositorViewport(const gfx::Rect& compositor_viewport); - protected: // --------------------------------------------------------------------------- // The following method is overridden by RenderViewHost to send upwards to @@ -1037,20 +1043,30 @@ // True if the render widget host should track the render widget's size as // opposed to visa versa. bool auto_resize_enabled_ = false; - // The minimum size for the render widget if auto-resize is enabled. gfx::Size min_size_for_auto_resize_; - // The maximum size for the render widget if auto-resize is enabled. gfx::Size max_size_for_auto_resize_; - // The page-scale factor of the main-frame. - float page_scale_factor_ = 1.f; + // These properties are propagated down the RenderWidget tree from the main + // frame to a child frame RenderWidgetHost. They are not used on a top-level + // RenderWidgetHost. The child frame RenderWidgetHost stores these values to + // pass them to the renderer, instead of computing them for itself. It + // collects them and passes them though WidgetMsg_UpdateVisualProperties so + // that the renderer receives updates in an atomic fashion along with a + // synchronization token for the compositor in a LocalSurfaceIdAllocation. + struct MainFramePropagationProperties { + // The page-scale factor of the main-frame. + float page_scale_factor = 1.f; - // True when the renderer is currently undergoing a pinch-zoom gesture. - bool is_pinch_gesture_active_ = false; + // True when the renderer is currently undergoing a pinch-zoom gesture. + bool is_pinch_gesture_active = false; - gfx::Rect compositor_viewport_; + // The size of the main frame's widget in DIP. + gfx::Size visible_viewport_size; + + gfx::Rect compositor_viewport; + } properties_from_parent_local_root_; bool waiting_for_screen_rects_ack_ = false; gfx::Rect last_view_screen_rect_;
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc index 1dcef0b..6fc2ae55 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -531,10 +531,6 @@ void RenderWidgetHostViewBase::DisableAutoResize(const gfx::Size& new_size) { if (!new_size.IsEmpty()) SetSize(new_size); - // This clears the cached value in the WebContents, so that OOPIFs will - // stop using it. - if (host()->delegate()) - host()->delegate()->ResetAutoResizeSize(); host()->SetAutoResize(false, gfx::Size(), gfx::Size()); host()->SynchronizeVisualProperties(); }
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc index 3e1df86c..709115ea 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -265,38 +265,15 @@ } gfx::Size RenderWidgetHostViewChildFrame::GetVisibleViewportSize() { - // For subframes, the visual viewport corresponds to the main frame size, so - // this bubbles up to the parent until it hits the main frame's - // RenderWidgetHostView. - // - // Currently this excludes webview guests, since they expect the visual - // viewport to return the guest's size rather than the page's; one reason why - // is that Blink ends up using the visual viewport to calculate things like - // window.innerWidth/innerHeight for main frames, and a guest is considered - // to be a main frame. This should be cleaned up eventually. - bool is_guest = BrowserPluginGuest::IsGuest(RenderViewHostImpl::From(host())); - if (frame_connector_ && !is_guest) { - // An auto-resize set by the top-level frame overrides what would be - // reported by embedding RenderWidgetHostViews. - if (host()->delegate() && - !host()->delegate()->GetAutoResizeSize().IsEmpty()) - return host()->delegate()->GetAutoResizeSize(); + // For subframes, the visual viewport corresponds to the main frame size so + // this method would not even be called, the main frame's value should be + // used instead. However a nested WebContents will have a ChildFrame view used + // for the main frame. + DCHECK(host()->owner_delegate()); - RenderWidgetHostView* parent_view = - frame_connector_->GetParentRenderWidgetHostView(); - // The parent_view can be null in unit tests when using a TestWebContents. - if (parent_view) - return parent_view->GetVisibleViewportSize(); - } - - gfx::Rect bounds = GetViewBounds(); - - // It doesn't make sense to set insets on an OOP iframe. The only time this - // should happen is when the virtual keyboard comes up on a <webview>. - if (is_guest) - bounds.Inset(insets_); - - return bounds.size(); + gfx::Rect requested_rect(GetRequestedRendererSize()); + requested_rect.Inset(insets_); + return requested_rect.size(); } void RenderWidgetHostViewChildFrame::SetInsets(const gfx::Insets& insets) {
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc index 2444928..50f70db 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc +++ b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
@@ -5,35 +5,47 @@ #include "content/browser/renderer_host/render_widget_host_view_child_frame.h" #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/macros.h" #include "base/run_loop.h" +#include "base/test/bind_test_util.h" +#include "base/test/scoped_feature_list.h" #include "base/test/test_timeouts.h" +#include "build/build_config.h" #include "components/viz/common/surfaces/surface_id.h" #include "content/browser/frame_host/frame_tree_node.h" +#include "content/browser/portal/portal.h" +#include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/frame_messages.h" #include "content/common/view_messages.h" +#include "content/common/widget_messages.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.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/test_navigation_observer.h" #include "content/public/test/test_utils.h" #include "content/shell/browser/shell.h" #include "content/test/content_browser_test_utils_internal.h" +#include "content/test/portal/portal_created_observer.h" #include "content/test/test_content_browser_client.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "third_party/blink/public/common/features.h" #include "ui/gfx/geometry/size.h" namespace content { -class RenderWidgetHostViewChildFrameTest : public ContentBrowserTest { +class RenderWidgetHostViewChildFrameBrowserTest : public ContentBrowserTest { public: - RenderWidgetHostViewChildFrameTest() {} + RenderWidgetHostViewChildFrameBrowserTest() = default; void SetUpCommandLine(base::CommandLine* command_line) override { IsolateAllSitesForTesting(command_line); + + scoped_feature_list_.InitAndEnableFeature(blink::features::kPortals); } void SetUpOnMainThread() override { @@ -42,13 +54,6 @@ ASSERT_TRUE(embedded_test_server()->Start()); } - void CheckScreenWidth(RenderFrameHost* render_frame_host) { - int width = - ExecuteScriptAndGetValue(render_frame_host, "window.screen.width") - .GetInt(); - EXPECT_EQ(expected_screen_width_, width); - } - // Tests that the FrameSinkId of each child frame has been updated by the // RenderFrameProxy. void CheckFrameSinkId(RenderFrameHost* render_frame_host) { @@ -76,6 +81,38 @@ actual_frame_sink_id_.sink_id()); } + Portal* CreatePortalToUrl(WebContentsImpl* host_contents, + GURL portal_url, + int number_of_navigations = 1) { + EXPECT_GE(number_of_navigations, 1); + RenderFrameHostImpl* main_frame = host_contents->GetMainFrame(); + + // Create portal and wait for navigation. + PortalCreatedObserver portal_created_observer(main_frame); + TestNavigationObserver navigation_observer(nullptr, number_of_navigations); + navigation_observer.set_wait_event( + TestNavigationObserver::WaitEvent::kNavigationFinished); + navigation_observer.StartWatchingNewWebContents(); + EXPECT_TRUE(ExecJs( + main_frame, JsReplace("{" + " let portal = document.createElement('portal');" + " portal.src = $1;" + " portal.setAttribute('id', 'portal');" + " document.body.appendChild(portal);" + "}", + portal_url))); + Portal* portal = portal_created_observer.WaitUntilPortalCreated(); + navigation_observer.StopWatchingNewWebContents(); + + WebContentsImpl* portal_contents = portal->GetPortalContents(); + EXPECT_TRUE(portal_contents); + + navigation_observer.WaitForNavigationFinished(); + EXPECT_TRUE(WaitForLoadStop(portal_contents)); + + return portal; + } + void GiveItSomeTime() { base::RunLoop run_loop; base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( @@ -87,17 +124,15 @@ expected_frame_sink_id_ = frame_sink_id; } - void set_expected_screen_width(int width) { expected_screen_width_ = width; } - private: + base::test::ScopedFeatureList scoped_feature_list_; viz::FrameSinkId expected_frame_sink_id_; - int expected_screen_width_; - DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewChildFrameTest); + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewChildFrameBrowserTest); }; // Tests that the screen is properly reflected for RWHVChildFrame. -IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameTest, Screen) { +IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameBrowserTest, Screen) { GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html")); EXPECT_TRUE(NavigateToURL(shell(), main_url)); @@ -114,51 +149,305 @@ ExecuteScriptAndGetValue(shell()->web_contents()->GetMainFrame(), "window.screen.width") .GetInt(); - set_expected_screen_width(main_frame_screen_width); EXPECT_NE(main_frame_screen_width, 0); + auto check_screen_width = [&](RenderFrameHost* frame_host) { + int width = + ExecuteScriptAndGetValue(frame_host, "window.screen.width").GetInt(); + EXPECT_EQ(width, main_frame_screen_width); + }; shell()->web_contents()->ForEachFrame( - base::BindRepeating(&RenderWidgetHostViewChildFrameTest::CheckScreenWidth, - base::Unretained(this))); + base::BindLambdaForTesting(check_screen_width)); } -// Test that auto-resize sizes in the top frame are propagated to OOPIF -// RenderWidgetHostViews. See https://crbug.com/726743. -IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameTest, - ChildFrameAutoResizeUpdate) { - EXPECT_TRUE(NavigateToURL( - shell(), embedded_test_server()->GetURL( - "a.com", "/cross_site_iframe_factory.html?a(b)"))); +class OutgoingVisualPropertiesIPCWatcher { + public: + OutgoingVisualPropertiesIPCWatcher( + RenderProcessHostImpl* rph, + base::RepeatingCallback<void(const VisualProperties&)> callback) + : rph_(rph), callback_(std::move(callback)) { + rph_->SetIpcSendWatcherForTesting( + base::BindRepeating(&OutgoingVisualPropertiesIPCWatcher::OnMessage, + base::Unretained(this))); + } + ~OutgoingVisualPropertiesIPCWatcher() { + rph_->SetIpcSendWatcherForTesting(base::NullCallback()); + } - FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) - ->GetFrameTree() - ->root(); - root->current_frame_host() - ->GetRenderWidgetHost() - ->GetView() - ->EnableAutoResize(gfx::Size(0, 0), gfx::Size(100, 100)); + private: + void OnMessage(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(OutgoingVisualPropertiesIPCWatcher, message) + IPC_MESSAGE_HANDLER(WidgetMsg_UpdateVisualProperties, ProcessMessage) + IPC_END_MESSAGE_MAP() + } - RenderWidgetHostView* rwhv = - root->child_at(0)->current_frame_host()->GetRenderWidgetHost()->GetView(); + void ProcessMessage(const VisualProperties& props) { callback_.Run(props); } - // Fake an auto-resize update from the parent renderer. - viz::LocalSurfaceId local_surface_id(10, 10, - base::UnguessableToken::Create()); - cc::RenderFrameMetadata metadata; - metadata.viewport_size_in_pixels = gfx::Size(75, 75); - metadata.local_surface_id_allocation = - viz::LocalSurfaceIdAllocation(local_surface_id, base::TimeTicks::Now()); - RenderFrameMetadataProvider::Observer* metadata_receiver = - root->current_frame_host()->GetRenderWidgetHost(); - metadata_receiver->OnLocalSurfaceIdChanged(metadata); + RenderProcessHostImpl* rph_; + base::RepeatingCallback<void(const VisualProperties&)> callback_; +}; - // The child frame's RenderWidgetHostView should now use the auto-resize value - // for its visible viewport. - EXPECT_EQ(gfx::Size(75, 75), rwhv->GetVisibleViewportSize()); +// Auto-resize is only implemented for Ash and GuestViews. So we need to inject +// an implementation that actually resizes the top level widget. +class AutoResizeWebContentsDelegate : public WebContentsDelegate { + void ResizeDueToAutoResize(WebContents* web_contents, + const gfx::Size& new_size) override { + RenderWidgetHostView* view = + web_contents->GetTopLevelRenderWidgetHostView(); + view->SetSize(new_size); + } +}; + +// Test that the |visible_viewport_size| from the top frame is propagated to all +// local roots (aka RenderWidgets): +// a) Initially upon adding the child frame (we create this scenario by +// navigating a child on b.com to c.com, where we already have a RenderProcess +// active for c.com). +// b) When resizing the top level widget. +// c) When auto-resize is enabled for the top level main frame and the renderer +// resizes the top level widget. +// d) When auto-resize is enabled for the nested main frame and the renderer +// resizes the nested widget. +// See https://crbug.com/726743 and https://crbug.com/1050635. +IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameBrowserTest, + VisualPropertiesPropagation_VisibleViewportSize) { + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b,c)")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + auto* web_contents = static_cast<WebContentsImpl*>(shell()->web_contents()); + FrameTreeNode* root = web_contents->GetFrameTree()->root(); + RenderWidgetHostView* root_view = + root->current_frame_host()->GetRenderWidgetHost()->GetView(); + + Portal* portal = CreatePortalToUrl(web_contents, main_url); + WebContentsImpl* nested_contents = portal->GetPortalContents(); + FrameTreeNode* nested_root = nested_contents->GetFrameTree()->root(); + RenderWidgetHostView* nested_root_view = + nested_root->current_frame_host()->GetRenderWidgetHost()->GetView(); + + // Watch processes for a.com and c.com, as we will throw away b.com when we + // navigate it below. + auto* root_rph = static_cast<RenderProcessHostImpl*>( + root->current_frame_host()->GetProcess()); + auto* child_rph = static_cast<RenderProcessHostImpl*>( + root->child_at(1)->current_frame_host()->GetProcess()); + ASSERT_NE(root_rph, child_rph); + + auto* nested_root_rph = static_cast<RenderProcessHostImpl*>( + nested_root->current_frame_host()->GetProcess()); + auto* nested_child_rph = static_cast<RenderProcessHostImpl*>( + nested_root->child_at(1)->current_frame_host()->GetProcess()); + ASSERT_NE(nested_root_rph, nested_child_rph); + + const gfx::Size initial_size = root_view->GetVisibleViewportSize(); + const gfx::Size nested_initial_size = + nested_root_view->GetVisibleViewportSize(); + ASSERT_NE(initial_size, nested_initial_size); + + // We should see the top level widget's size in the visible_viewport_size + // in both local roots. When a child local root is added in the parent + // renderer, the value is propagated down through the browser to the child + // renderer's RenderWidget. + // + // This property is not directly visible in the renderer, so we can only + // check that the value is sent to the appropriate RenderWidget. + { + base::RunLoop loop; + + gfx::Size child_visible_viewport_size; + OutgoingVisualPropertiesIPCWatcher child_watcher( + child_rph, + base::BindLambdaForTesting([&](const VisualProperties& props) { + child_visible_viewport_size = props.visible_viewport_size; + + if (child_visible_viewport_size == initial_size) + loop.Quit(); + })); + + GURL cross_site_url( + embedded_test_server()->GetURL("c.com", "/title2.html")); + NavigateFrameToURL(root->child_at(0), cross_site_url); + + // Wait to see the size sent to the child RenderWidget. + loop.Run(); + + // The child widget was also informed of the same size. + EXPECT_EQ(initial_size, child_visible_viewport_size); + } + + // Same check as abvoe but for a nested WebContents. + { + base::RunLoop loop; + + gfx::Size child_visible_viewport_size; + OutgoingVisualPropertiesIPCWatcher child_watcher( + nested_child_rph, + base::BindLambdaForTesting([&](const VisualProperties& props) { + child_visible_viewport_size = props.visible_viewport_size; + + if (child_visible_viewport_size == nested_initial_size) + loop.Quit(); + })); + + GURL cross_site_url( + embedded_test_server()->GetURL("c.com", "/title2.html")); + NavigateFrameToURL(nested_root->child_at(0), cross_site_url); + + // Wait to see the size sent to the child RenderWidget. + loop.Run(); + + // The child widget was also informed of the same size. + EXPECT_EQ(nested_initial_size, child_visible_viewport_size); + } + +// This part of the test does not work well on Android, for a few reasons: +// 1. RenderWidgetHostViewAndroid can not be resized, the Java objects need to +// be resized somehow through ui::ViewAndroid. +// 2. AutoResize on Android does not size to the min/max bounds specified, it +// ends up ignoring them and sizing to the screen (I think). +// Luckily this test is verifying interactions and behaviour of +// RenderWidgetHostImpl - RenderWidget - RenderFrameProxy - +// CrossProcessFrameConnector, and this isn't Android-specific code. +#if !defined(OS_ANDROID) + + // Resize the top level widget to cause its |visible_viewport_size| to be + // changed. The change should propagate down to the child RenderWidget. + { + base::RunLoop loop; + + const gfx::Size resize_to(initial_size.width() - 10, + initial_size.height() - 10); + + gfx::Size root_visible_viewport_size; + gfx::Size child_visible_viewport_size; + OutgoingVisualPropertiesIPCWatcher root_watcher( + root_rph, + base::BindLambdaForTesting([&](const VisualProperties& props) { + root_visible_viewport_size = props.visible_viewport_size; + })); + OutgoingVisualPropertiesIPCWatcher child_watcher( + child_rph, + base::BindLambdaForTesting([&](const VisualProperties& props) { + child_visible_viewport_size = props.visible_viewport_size; + + if (child_visible_viewport_size == resize_to) + loop.Quit(); + })); + + root_view->SetSize(resize_to); + + // Wait to see both RenderWidgets receive the message. + loop.Run(); + + // The top level widget was resized. + EXPECT_EQ(resize_to, root_visible_viewport_size); + // The child widget was also informed of the same size. + EXPECT_EQ(resize_to, child_visible_viewport_size); + } + + // Same check as above but resizing the nested WebContents' main frame + // instead. + // Resize the top level widget to cause its |visible_viewport_size| to be + // changed. The change should propagate down to the child RenderWidget. + { + base::RunLoop loop; + + const gfx::Size resize_to(nested_initial_size.width() - 10, + nested_initial_size.height() - 10); + + gfx::Size root_visible_viewport_size; + gfx::Size child_visible_viewport_size; + OutgoingVisualPropertiesIPCWatcher root_watcher( + nested_root_rph, + base::BindLambdaForTesting([&](const VisualProperties& props) { + root_visible_viewport_size = props.visible_viewport_size; + })); + OutgoingVisualPropertiesIPCWatcher child_watcher( + nested_child_rph, + base::BindLambdaForTesting([&](const VisualProperties& props) { + child_visible_viewport_size = props.visible_viewport_size; + + if (child_visible_viewport_size == resize_to) + loop.Quit(); + })); + + EXPECT_TRUE(ExecJs( + root->current_frame_host(), + JsReplace("document.getElementById('portal').style.width = '$1px';" + "document.getElementById('portal').style.height = '$2px';", + resize_to.width(), resize_to.height()))); + + // Wait to see both RenderWidgets receive the message. + loop.Run(); + + // The top level widget was resized. + EXPECT_EQ(resize_to, root_visible_viewport_size); + // The child widget was also informed of the same size. + EXPECT_EQ(resize_to, child_visible_viewport_size); + } + + // Informs the top-level frame it can auto-resize. It will shrink down to its + // minimum window size based on the empty content we've loaded, which is + // 100x100. + // + // When the renderer resizes, thanks to our AutoResizeWebContentsDelegate + // the top level widget will resize. That size will be reflected in the + // visible_viewport_size which is sent back through the top level RenderWidget + // to propagte down to child local roots. + // + // This property is not directly visible in the renderer, so we can only + // check that the value is sent to both RenderWidgets. + { + base::RunLoop loop; + + const gfx::Size auto_resize_to(105, 100); + + gfx::Size root_visible_viewport_size; + gfx::Size child_visible_viewport_size; + OutgoingVisualPropertiesIPCWatcher root_watcher( + root_rph, + base::BindLambdaForTesting([&](const VisualProperties& props) { + root_visible_viewport_size = props.visible_viewport_size; + })); + OutgoingVisualPropertiesIPCWatcher child_watcher( + child_rph, + base::BindLambdaForTesting([&](const VisualProperties& props) { + child_visible_viewport_size = props.visible_viewport_size; + + if (child_visible_viewport_size == auto_resize_to) + loop.Quit(); + })); + + // Replace the WebContentsDelegate so that we can use the auto-resize + // changes to adjust the size of the top widget. + WebContentsDelegate* old_delegate = shell()->web_contents()->GetDelegate(); + AutoResizeWebContentsDelegate resize_delegate; + shell()->web_contents()->SetDelegate(&resize_delegate); + + root_view->EnableAutoResize(auto_resize_to, auto_resize_to); + + // Wait for the renderer side to resize itself and the RenderWidget + // waterfall to pass the new |visible_viewport_size| down. + loop.Run(); + + // The top level widget was resized to match the auto-resized renderer. + EXPECT_EQ(auto_resize_to, root_visible_viewport_size); + // The child widget was also informed of the same size. + EXPECT_EQ(auto_resize_to, child_visible_viewport_size); + + shell()->web_contents()->SetDelegate(old_delegate); + } + + // TODO(danakj): We'd like to run the same check as above but tell the main + // frame of the nested WebContents that it can auto-resize. However this seems + // to get through to the main frame's RenderWidget and propagate correctly but + // no size change occurs in the renderer. +#endif } // Validate that OOPIFs receive presentation feedbacks. -IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameTest, +IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameBrowserTest, PresentationFeedback) { base::HistogramTester histogram_tester; GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc index 09119efd..eee6eef6 100644 --- a/content/browser/service_worker/embedded_worker_instance.cc +++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -76,6 +76,16 @@ std::move(host_receiver)); } +void NotifyUpdateCrossOriginEmbedderPolicyOnUI( + int worker_process_id, + int worker_route_id, + network::CrossOriginEmbedderPolicy cross_origin_embedder_policy) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + ServiceWorkerDevToolsManager::GetInstance()->UpdateCrossOriginEmbedderPolicy( + worker_process_id, worker_route_id, + std::move(cross_origin_embedder_policy)); +} + void NotifyWorkerDestroyedOnUI(int worker_process_id, int worker_route_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); ServiceWorkerDevToolsManager::GetInstance()->WorkerDestroyed( @@ -106,7 +116,6 @@ , std::unique_ptr< blink::PendingURLLoaderFactoryBundle> /* factory_bundle_for_renderer */, - mojo::PendingRemote<blink::mojom::CacheStorage>, const base::Optional<base::TimeDelta>& thread_hop_time, const base::Optional<base::Time>& ui_post_time)>; @@ -124,7 +133,8 @@ int embedded_worker_id, base::WeakPtr<ServiceWorkerProcessManager> process_manager, bool can_use_existing_process, - const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy, + const base::Optional<network::CrossOriginEmbedderPolicy>& + cross_origin_embedder_policy, blink::mojom::EmbeddedWorkerStartParamsPtr params, mojo::PendingReceiver<blink::mojom::EmbeddedWorkerInstanceClient> receiver, ServiceWorkerContextCore* context, @@ -156,7 +166,6 @@ std::move(devtools_proxy), std::move(factory_bundle_for_new_scripts), std::move(factory_bundle_for_renderer), - mojo::NullRemote() /* cache_storage */, thread_hop_time, ui_post_time)); return; } @@ -176,8 +185,7 @@ base::BindOnce(std::move(callback), status, std::move(params), std::move(process_info), std::move(devtools_proxy), std::move(factory_bundle_for_new_scripts), - std::move(factory_bundle_for_renderer), - mojo::NullRemote() /* cache_storage */, thread_hop_time, + std::move(factory_bundle_for_renderer), thread_hop_time, ui_post_time)); return; } @@ -188,18 +196,6 @@ // rph->IsInitializedAndNotDead(). CHECK(rph); - // Create cache storage now as an optimization, so the service worker can use - // the Cache Storage API immediately on startup. - mojo::PendingRemote<blink::mojom::CacheStorage> cache_storage; - if (base::FeatureList::IsEnabled( - blink::features::kEagerCacheStorageSetupForServiceWorkers)) { - // TODO(https://crbug.com/1031542): Add support enforcing CORP in - // cache.match() for ServiceWorker. - rph->BindCacheStorage(network::CrossOriginEmbedderPolicy(), - url::Origin::Create(params->script_url), - cache_storage.InitWithNewPipeAndPassReceiver()); - } - // Bind |receiver|, which is attached to |EmbeddedWorkerInstance::client_|, to // the process. If the process dies, |client_|'s connection error callback // will be called on the core thread. @@ -211,8 +207,8 @@ ServiceWorkerDevToolsManager::GetInstance()->WorkerCreated( process_id, routing_id, context, weak_context, params->service_worker_version_id, params->script_url, params->scope, - params->is_installed, ¶ms->devtools_worker_token, - ¶ms->wait_for_debugger); + params->is_installed, cross_origin_embedder_policy, + ¶ms->devtools_worker_token, ¶ms->wait_for_debugger); params->service_worker_route_id = routing_id; // Create DevToolsProxy here to ensure that the WorkerCreated() call is // balanced by DevToolsProxy's destructor calling WorkerDestroyed(). @@ -267,8 +263,8 @@ base::BindOnce(std::move(callback), status, std::move(params), std::move(process_info), std::move(devtools_proxy), std::move(factory_bundle_for_new_scripts), - std::move(factory_bundle_for_renderer), - std::move(cache_storage), thread_hop_time, ui_post_time)); + std::move(factory_bundle_for_renderer), thread_hop_time, + ui_post_time)); } bool HasSentStartWorker(EmbeddedWorkerInstance::StartingPhase phase) { @@ -301,6 +297,20 @@ rph->OnForegroundServiceWorkerRemoved(); } +void BindCacheStorageOnUIThread( + int process_id, + url::Origin origin, + network::CrossOriginEmbedderPolicy cross_origin_embedder_policy, + mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + auto* rph = RenderProcessHost::FromID(process_id); + if (!rph) + return; + + rph->BindCacheStorage(cross_origin_embedder_policy, origin, + std::move(receiver)); +} + } // namespace // Created on UI thread and moved to core thread. Proxies notifications to @@ -340,6 +350,21 @@ } } + void NotifyUpdateCrossOriginEmbedderPolicy( + network::CrossOriginEmbedderPolicy cross_origin_embedder_policy) { + DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { + NotifyUpdateCrossOriginEmbedderPolicyOnUI( + process_id_, agent_route_id_, + std::move(cross_origin_embedder_policy)); + } else { + ui_task_runner_->PostTask( + FROM_HERE, base::BindOnce(NotifyUpdateCrossOriginEmbedderPolicyOnUI, + process_id_, agent_route_id_, + std::move(cross_origin_embedder_policy))); + } + } + void NotifyWorkerVersionInstalled() { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { @@ -528,10 +553,10 @@ return skip_recording_startup_time_; } - void Start( - blink::mojom::EmbeddedWorkerStartParamsPtr params, - const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy, - StatusCallback sent_start_callback) { + void Start(blink::mojom::EmbeddedWorkerStartParamsPtr params, + const base::Optional<network::CrossOriginEmbedderPolicy>& + cross_origin_embedder_policy, + StatusCallback sent_start_callback) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK(instance_->context_); TRACE_EVENT_WITH_FLOW0( @@ -559,7 +584,7 @@ if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { SetupOnUIThread( instance_->embedded_worker_id(), process_manager, - can_use_existing_process, std::move(cross_origin_embedder_policy), + can_use_existing_process, cross_origin_embedder_policy, std::move(params), std::move(receiver_), context.get(), context, base::nullopt, base::BindOnce(&StartTask::OnSetupCompleted, @@ -570,7 +595,7 @@ base::BindOnce( &SetupOnUIThread, instance_->embedded_worker_id(), process_manager, can_use_existing_process, - std::move(cross_origin_embedder_policy), std::move(params), + cross_origin_embedder_policy, std::move(params), std::move(receiver_), context.get(), context, base::make_optional<base::Time>(base::Time::Now()), base::BindOnce(&StartTask::OnSetupCompleted, @@ -592,7 +617,6 @@ factory_bundle_for_new_scripts, std::unique_ptr<blink::PendingURLLoaderFactoryBundle> factory_bundle_for_renderer, - mojo::PendingRemote<blink::mojom::CacheStorage> cache_storage, const base::Optional<base::TimeDelta>& thread_hop_time, const base::Optional<base::Time>& ui_post_time) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); @@ -665,7 +689,13 @@ std::move(factory_bundle_for_new_scripts)); } - params->provider_info->cache_storage = std::move(cache_storage); + // Create cache storage now as an optimization, so the service worker can + // use the Cache Storage API immediately on startup. + if (base::FeatureList::IsEnabled( + blink::features::kEagerCacheStorageSetupForServiceWorkers)) { + instance_->BindCacheStorage(params->provider_info->cache_storage + .InitWithNewPipeAndPassReceiver()); + } instance_->SendStartWorker(std::move(params)); std::move(sent_start_callback_).Run(blink::ServiceWorkerStatusCode::kOk); @@ -901,10 +931,18 @@ if (!inflight_start_task_) return; + // COEP could be nullopt if it's in unittests. + // TODO(shimazu): Set COEP in the failing unit tests. + if (devtools_proxy_ && owner_version_->cross_origin_embedder_policy()) { + devtools_proxy_->NotifyUpdateCrossOriginEmbedderPolicy( + owner_version_->cross_origin_embedder_policy().value()); + } + // Renderer side has started to launch the worker thread. starting_phase_ = SCRIPT_LOADED; owner_version_->OnMainScriptLoaded(); - // |this| may be destroyed by the callback. + + BindCacheStorageInternal(); } void EmbeddedWorkerInstance::OnWorkerVersionInstalled() { @@ -1026,6 +1064,13 @@ } } +void EmbeddedWorkerInstance::BindCacheStorage( + mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) { + DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + pending_cache_storage_receivers_.push_back(std::move(receiver)); + BindCacheStorageInternal(); +} + base::WeakPtr<EmbeddedWorkerInstance> EmbeddedWorkerInstance::AsWeakPtr() { return weak_factory_.GetWeakPtr(); } @@ -1040,7 +1085,8 @@ RenderProcessHost* rph, int routing_id, const url::Origin& origin, - const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy, + const base::Optional<network::CrossOriginEmbedderPolicy>& + cross_origin_embedder_policy, ContentBrowserClient::URLLoaderFactoryType factory_type) { DCHECK_CURRENTLY_ON(BrowserThread::UI); auto factory_bundle = @@ -1070,8 +1116,14 @@ factory_params->client_security_state = network::mojom::ClientSecurityState::New(); + + // Without PlzServiceWorker, the COEP header might no be known initially for + // new ServiceWorker. The default COEP header is used instead here. Later, the + // subresource loader factories will be updated with the correct COEP header. + // See: https://chromium-review.googlesource.com/c/chromium/src/+/2029403 factory_params->client_security_state->cross_origin_embedder_policy = - std::move(cross_origin_embedder_policy); + cross_origin_embedder_policy ? cross_origin_embedder_policy.value() + : network::CrossOriginEmbedderPolicy(); rph->CreateURLLoaderFactory(std::move(default_factory_receiver), std::move(factory_params)); @@ -1291,4 +1343,23 @@ return script_loader_factory_remote; } +void EmbeddedWorkerInstance::BindCacheStorageInternal() { + DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + // Without PlzServiceWorker, the COEP header might not be known initially. + // The in-flight CacheStorage requests are kept until the main script has + // loaded the headers and the COEP one is known. + if (!owner_version_->cross_origin_embedder_policy()) + return; + + for (auto& receiver : pending_cache_storage_receivers_) { + RunOrPostTaskOnThread( + FROM_HERE, BrowserThread::UI, + base::BindOnce(content::BindCacheStorageOnUIThread, process_id(), + owner_version_->script_origin(), + owner_version_->cross_origin_embedder_policy().value(), + std::move(receiver))); + } + pending_cache_storage_receivers_.clear(); +} + } // namespace content
diff --git a/content/browser/service_worker/embedded_worker_instance.h b/content/browser/service_worker/embedded_worker_instance.h index cc4a164..7079655c 100644 --- a/content/browser/service_worker/embedded_worker_instance.h +++ b/content/browser/service_worker/embedded_worker_instance.h
@@ -220,6 +220,9 @@ std::unique_ptr<blink::PendingURLLoaderFactoryBundle> script_bundle, std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_bundle); + void BindCacheStorage( + mojo::PendingReceiver<blink::mojom::CacheStorage> receiver); + base::WeakPtr<EmbeddedWorkerInstance> AsWeakPtr(); // The below can only be called on the UI thread. The returned factory may be @@ -229,7 +232,8 @@ RenderProcessHost* rph, int routing_id, const url::Origin& origin, - const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy, + const base::Optional<network::CrossOriginEmbedderPolicy>& + cross_origin_embedder_policy, ContentBrowserClient::URLLoaderFactoryType factory_type); private: @@ -304,6 +308,8 @@ MakeScriptLoaderFactoryRemote( std::unique_ptr<blink::PendingURLLoaderFactoryBundle> script_bundle); + void BindCacheStorageInternal(); + base::WeakPtr<ServiceWorkerContextCore> context_; ServiceWorkerVersion* owner_version_; @@ -362,6 +368,11 @@ mojo::Remote<blink::mojom::SubresourceLoaderUpdater> subresource_loader_updater_; + // Hold in-flight CacheStorage requests. They will be bound when the + // ServiceWorker COEP header will be known. + std::vector<mojo::PendingReceiver<blink::mojom::CacheStorage>> + pending_cache_storage_receivers_; + base::WeakPtrFactory<EmbeddedWorkerInstance> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstance);
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc index 8a036eb..ea6396cb 100644 --- a/content/browser/service_worker/service_worker_job_unittest.cc +++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -2069,8 +2069,7 @@ scoped_refptr<ServiceWorkerRegistration> registration = update_helper_->SetupInitialRegistration(kNewVersionOrigin); ASSERT_TRUE(registration.get()); - EXPECT_EQ(CrossOriginEmbedderPolicyNone(), - registration->active_version()->cross_origin_embedder_policy()); + EXPECT_FALSE(registration->active_version()->cross_origin_embedder_policy()); registration->AddListener(update_helper_);
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc index 08a2349..68e512f5 100644 --- a/content/browser/service_worker/service_worker_provider_host.cc +++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -22,6 +22,7 @@ #include "content/public/common/child_process_host.h" #include "content/public/common/origin_util.h" #include "mojo/public/cpp/bindings/message.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/messaging/message_port_channel.h" #include "third_party/blink/public/common/service_worker/service_worker_utils.h" #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom.h" @@ -110,6 +111,15 @@ std::move(receiver))); } +void ServiceWorkerProviderHost::BindCacheStorage( + mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) { + DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + DCHECK(!base::FeatureList::IsEnabled( + blink::features::kEagerCacheStorageSetupForServiceWorkers)); + running_hosted_version_->embedded_worker()->BindCacheStorage( + std::move(receiver)); +} + base::WeakPtr<ServiceWorkerProviderHost> ServiceWorkerProviderHost::GetWeakPtr() { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h index 1307bb24..b65bd3c 100644 --- a/content/browser/service_worker/service_worker_provider_host.h +++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -70,6 +70,9 @@ void CreateQuicTransportConnector( mojo::PendingReceiver<blink::mojom::QuicTransportConnector> receiver); + // Used only when EagerCacheStorageSetupForServiceWorkers is disabled. + void BindCacheStorage( + mojo::PendingReceiver<blink::mojom::CacheStorage> receiver); content::ServiceWorkerContainerHost* container_host() { return container_host_.get();
diff --git a/content/browser/service_worker/service_worker_registry.cc b/content/browser/service_worker/service_worker_registry.cc index 30316d84..bee7dce 100644 --- a/content/browser/service_worker/service_worker_registry.cc +++ b/content/browser/service_worker/service_worker_registry.cc
@@ -311,7 +311,13 @@ data->script_response_time = version->GetInfo().script_response_time; for (const blink::mojom::WebFeature feature : version->used_features()) data->used_features.push_back(feature); - data->cross_origin_embedder_policy = version->cross_origin_embedder_policy(); + + // The ServiceWorkerVersion's COEP might be null if it is stored before + // loading the main script. This happens in many unittests. + if (version->cross_origin_embedder_policy()) { + data->cross_origin_embedder_policy = + version->cross_origin_embedder_policy().value(); + } auto resources = std::make_unique<ResourceList>(); version->script_cache_map()->GetResources(resources.get());
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index aaaa8e31..64c3b10 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -212,7 +212,8 @@ int process_id, int routing_id, const url::Origin& origin, - network::CrossOriginEmbedderPolicy cross_origin_embedder_policy, + base::Optional<network::CrossOriginEmbedderPolicy> + cross_origin_embedder_policy, CreateFactoryBundleForSubresourceOnUICallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); auto* rph = RenderProcessHost::FromID(process_id); @@ -1688,6 +1689,14 @@ container_host_by_uuid.second->CountFeature(feature); } +void ServiceWorkerVersion::set_cross_origin_embedder_policy( + network::CrossOriginEmbedderPolicy cross_origin_embedder_policy) { + // Once it is set, the CrossOriginEmbedderPolicy is immutable. + DCHECK(!cross_origin_embedder_policy_ || + cross_origin_embedder_policy_ == cross_origin_embedder_policy); + cross_origin_embedder_policy_ = std::move(cross_origin_embedder_policy); +} + // static bool ServiceWorkerVersion::IsInstalled(ServiceWorkerVersion::Status status) { switch (status) { @@ -2330,7 +2339,7 @@ network::CrossOriginEmbedderPolicy cross_origin_embedder_policy) { compared_script_info_map_ = std::move(compared_script_info_map); updated_script_url_ = updated_script_url; - cross_origin_embedder_policy_ = cross_origin_embedder_policy; + set_cross_origin_embedder_policy(cross_origin_embedder_policy); } const std::map<GURL, ServiceWorkerUpdateChecker::ComparedScriptInfo>&
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index 3c725c3..288ab528 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -521,10 +521,9 @@ } void set_cross_origin_embedder_policy( - network::CrossOriginEmbedderPolicy cross_origin_embedder_policy) { - cross_origin_embedder_policy_ = cross_origin_embedder_policy; - } - network::CrossOriginEmbedderPolicy cross_origin_embedder_policy() const { + network::CrossOriginEmbedderPolicy cross_origin_embedder_policy); + const base::Optional<network::CrossOriginEmbedderPolicy>& + cross_origin_embedder_policy() const { return cross_origin_embedder_policy_; } @@ -901,9 +900,17 @@ ServiceWorkerMetrics::Site site_for_uma_; // Cross-Origin-Embedder-Policy for the service worker script. This persists - // in the disk. kNone is set if this is a brand-new service worker whose main - // script is not loaded yet. - network::CrossOriginEmbedderPolicy cross_origin_embedder_policy_; + // in the disk. + // + // On brand new service workers, the COEP value is not known initially. It + // will be set in PrepareForUpdate(), after the main script has been processed + // by the renderer process. + // + // PlzServiceWorker(https://crbug.com/996511): + // Once landed, there is no more need to use an base::Optional here. The COEP + // header is going to be known from the beginning and can be mark as 'const'. + base::Optional<network::CrossOriginEmbedderPolicy> + cross_origin_embedder_policy_; Status status_ = NEW; std::unique_ptr<EmbeddedWorkerInstance> embedded_worker_;
diff --git a/content/browser/service_worker/service_worker_version_browsertest.cc b/content/browser/service_worker/service_worker_version_browsertest.cc index cee0621..02faf88 100644 --- a/content/browser/service_worker/service_worker_version_browsertest.cc +++ b/content/browser/service_worker/service_worker_version_browsertest.cc
@@ -1655,8 +1655,7 @@ RunOnCoreThread(base::BindOnce( &ServiceWorkerVersionBrowserTest::SetUpRegistrationOnCoreThread, base::Unretained(this), "/service_worker/generated")); - EXPECT_EQ(CrossOriginEmbedderPolicyNone(), - version_->cross_origin_embedder_policy()); + EXPECT_FALSE(version_->cross_origin_embedder_policy()); // Once it's started, the worker script is read from the network and the COEP // value is set to the version.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 2b5e6c8..056153a0 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1634,29 +1634,6 @@ GetOuterWebContents()->NotifyNavigationStateChanged(changed_flags); } -void WebContentsImpl::NotifyVisibleViewportSizeChanged( - const gfx::Size& visible_viewport_size) { - // This viewport size is in screen coordinates, but will be handed to blink - // which expects coordinates including the device scale factor when - // UseZoomForDSF is enabled. - // TODO(danakj): This scaling should be done in the renderer where emulation - // may override the device scale factor. - gfx::Size visible_viewport_size_for_blink = visible_viewport_size; - if (IsUseZoomForDSFEnabled()) { - ScreenInfo info; - GetMainFrame()->GetRenderWidgetHost()->GetScreenInfo(&info); - - visible_viewport_size_for_blink = - gfx::ScaleToCeiledSize(visible_viewport_size, info.device_scale_factor); - } - - // TODO(danakj): This should be part of VisualProperties and walk down the - // RenderWidget tree like other VisualProperties do, in order to set the - // value in each WebView holds a part of the local frame tree. - SendPageMessage(new PageMsg_UpdatePageVisualProperties( - MSG_ROUTING_NONE, visible_viewport_size_for_blink)); -} - RenderFrameHostImpl* WebContentsImpl::GetFocusedFrameFromFocusedDelegate() { FrameTreeNode* focused_node = GetFocusedWebContents()->frame_tree_.GetFocusedFrame(); @@ -2070,14 +2047,6 @@ if (!params.last_active_time.is_null()) last_active_time_ = params.last_active_time; - // The routing ids must either all be set or all be unset. - DCHECK((params.routing_id == MSG_ROUTING_NONE && - params.main_frame_routing_id == MSG_ROUTING_NONE && - params.main_frame_widget_routing_id == MSG_ROUTING_NONE) || - (params.routing_id != MSG_ROUTING_NONE && - params.main_frame_routing_id != MSG_ROUTING_NONE && - params.main_frame_widget_routing_id != MSG_ROUTING_NONE)); - scoped_refptr<SiteInstance> site_instance = params.site_instance; if (!site_instance) site_instance = SiteInstance::Create(params.browser_context); @@ -2086,24 +2055,9 @@ ->PreventAssociationWithSpareProcess(); } - // A main RenderFrameHost always has a RenderWidgetHost, since it is always a - // local root by definition. - // TODO(avi): Once RenderViewHostImpl has-a RenderWidgetHostImpl, it will no - // longer be necessary to eagerly grab a routing ID for the view. - // https://crbug.com/545684 - int32_t view_routing_id = params.routing_id; - int32_t main_frame_widget_routing_id = params.main_frame_widget_routing_id; - if (main_frame_widget_routing_id == MSG_ROUTING_NONE) { - view_routing_id = site_instance->GetProcess()->GetNextRoutingID(); - main_frame_widget_routing_id = - site_instance->GetProcess()->GetNextRoutingID(); - } - - DCHECK_NE(view_routing_id, main_frame_widget_routing_id); - - GetRenderManager()->Init( - site_instance.get(), view_routing_id, params.main_frame_routing_id, - main_frame_widget_routing_id, params.renderer_initiated_creation); + GetRenderManager()->Init(site_instance.get(), + /*frame_routing_id=*/MSG_ROUTING_NONE, + params.renderer_initiated_creation); // blink::FrameTree::setName always keeps |unique_name| empty in case of a // main frame - let's do the same thing here. @@ -2938,22 +2892,6 @@ // objects. create_params.renderer_initiated_creation = !is_new_browsing_instance; - // If |is_new_browsing_instance| is true, defer routing_id allocation - // to the WebContentsImpl::Create() call. This is required because with - // a new browsing instance, WebContentsImpl::Create() may elect a different - // SiteInstance from |site_instance| (which happens if |site_instance| is - // nullptr for example). - // - // TODO(ajwong): This routing id allocation should be pushed down further - // into WebContentsImpl::Create(). - if (!is_new_browsing_instance) { - create_params.routing_id = opener->GetProcess()->GetNextRoutingID(); - create_params.main_frame_routing_id = - opener->GetProcess()->GetNextRoutingID(); - create_params.main_frame_widget_routing_id = - opener->GetProcess()->GetNextRoutingID(); - } - std::unique_ptr<WebContentsImpl> new_contents; if (!is_guest) { create_params.context = view_->GetNativeView(); @@ -2996,9 +2934,10 @@ // TODO(ajwong): This should be keyed off the RenderFrame routing id or the // FrameTreeNode id instead of the routing id of the Widget for the main // frame. https://crbug.com/545684 - DCHECK_NE(MSG_ROUTING_NONE, create_params.main_frame_routing_id); - GlobalRoutingID id(render_process_id, - create_params.main_frame_widget_routing_id); + int32_t main_frame_routing_id = new_contents_impl->GetMainFrame() + ->GetRenderWidgetHost() + ->GetRoutingID(); + GlobalRoutingID id(render_process_id, main_frame_routing_id); pending_contents_[id] = std::move(new_contents); AddDestructionObserver(new_contents_impl); } @@ -3568,32 +3507,10 @@ if (render_widget_host != GetRenderViewHost()->GetWidget()) return; - auto_resize_size_ = new_size; - - // Out-of-process iframe visible viewport sizes usually come from the - // top-level RenderWidgetHostView, but when auto-resize is enabled on the - // top frame then that size is used instead. - for (FrameTreeNode* node : frame_tree_.Nodes()) { - if (node->current_frame_host()->is_local_root()) { - RenderWidgetHostImpl* host = - node->current_frame_host()->GetRenderWidgetHost(); - if (host != render_widget_host) - host->SynchronizeVisualProperties(); - } - } - if (delegate_) delegate_->ResizeDueToAutoResize(this, new_size); } -gfx::Size WebContentsImpl::GetAutoResizeSize() { - return auto_resize_size_; -} - -void WebContentsImpl::ResetAutoResizeSize() { - auto_resize_size_ = gfx::Size(); -} - WebContents* WebContentsImpl::OpenURL(const OpenURLParams& params) { #if DCHECK_IS_ON() DCHECK(params.Valid());
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 7ac8d4ba..c3731f17 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -826,10 +826,6 @@ bool width_changed) override; void ResizeDueToAutoResize(RenderWidgetHostImpl* render_widget_host, const gfx::Size& new_size) override; - gfx::Size GetAutoResizeSize() override; - void ResetAutoResizeSize() override; - void NotifyVisibleViewportSizeChanged( - const gfx::Size& visible_viewport_size) override; RenderFrameHostImpl* GetFocusedFrameFromFocusedDelegate() override; void OnVerticalScrollDirectionChanged( viz::VerticalScrollDirection scroll_direction) override; @@ -1806,10 +1802,6 @@ // this overrides |preferred_size_|. gfx::Size preferred_size_for_capture_; - // Size set by a top-level frame with auto-resize enabled. This is needed by - // out-of-process iframes for their visible viewport size. - gfx::Size auto_resize_size_; - // When device emulation is enabled, override the size of current and newly // created render views/widgets. gfx::Size device_emulation_size_;
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc index fcc4e6ce..0b7b2be 100644 --- a/content/browser/worker_host/dedicated_worker_host.cc +++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -394,6 +394,13 @@ std::move(receiver)); } +void DedicatedWorkerHost::BindCacheStorage( + mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + worker_process_host_->BindCacheStorage(cross_origin_embedder_policy_, + worker_origin_, std::move(receiver)); +} + void DedicatedWorkerHost::CreateNestedDedicatedWorker( mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver) { DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/content/browser/worker_host/dedicated_worker_host.h b/content/browser/worker_host/dedicated_worker_host.h index 03bfd609..0e947e1 100644 --- a/content/browser/worker_host/dedicated_worker_host.h +++ b/content/browser/worker_host/dedicated_worker_host.h
@@ -80,10 +80,6 @@ RenderProcessHost* GetProcessHost() { return worker_process_host_; } const url::Origin& GetWorkerOrigin() { return worker_origin_; } - const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy() - const { - return cross_origin_embedder_policy_; - } void CreateIdleManager( mojo::PendingReceiver<blink::mojom::IdleManager> receiver); @@ -97,6 +93,8 @@ mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver); void CreateQuicTransportConnector( mojo::PendingReceiver<blink::mojom::QuicTransportConnector> receiver); + void BindCacheStorage( + mojo::PendingReceiver<blink::mojom::CacheStorage> receiver); #if !defined(OS_ANDROID) void BindSerialService(
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc index 8ae2dc6d..c0bc9d3 100644 --- a/content/browser/worker_host/shared_worker_host.cc +++ b/content/browser/worker_host/shared_worker_host.cc
@@ -337,6 +337,17 @@ std::move(receiver)); } +void SharedWorkerHost::BindCacheStorage( + mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + // TODO(https://crbug.com/1031542): Add support enforcing CORP in + // cache.match() for SharedWorker by providing the correct value here. + network::CrossOriginEmbedderPolicy cross_origin_embedder_policy; + const url::Origin origin = url::Origin::Create(instance().url()); + worker_process_host_->BindCacheStorage(cross_origin_embedder_policy, origin, + std::move(receiver)); +} + void SharedWorkerHost::Destruct() { // Ask the service to destroy |this| which will terminate the worker. service_->DestroyHost(this);
diff --git a/content/browser/worker_host/shared_worker_host.h b/content/browser/worker_host/shared_worker_host.h index bcbf0ce..3a7bddea 100644 --- a/content/browser/worker_host/shared_worker_host.h +++ b/content/browser/worker_host/shared_worker_host.h
@@ -108,6 +108,8 @@ mojo::PendingReceiver<blink::mojom::AppCacheBackend> receiver); void CreateQuicTransportConnector( mojo::PendingReceiver<blink::mojom::QuicTransportConnector> receiver); + void BindCacheStorage( + mojo::PendingReceiver<blink::mojom::CacheStorage> receiver); // Causes this instance to be deleted, which will terminate the worker. May // be done based on a UI action.
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc index 921dcd8..36574e6 100644 --- a/content/child/child_thread_impl.cc +++ b/content/child/child_thread_impl.cc
@@ -10,7 +10,7 @@ #include "base/base_switches.h" #include "base/bind.h" -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/debug/alias.h" @@ -84,7 +84,7 @@ #include "base/mac/mach_port_rendezvous.h" #endif -#if BUILDFLAG(CLANG_COVERAGE_INSIDE_SANDBOX) +#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) #include <stdio.h> #if defined(OS_WIN) #include <io.h> @@ -372,8 +372,8 @@ weak_main_thread_, std::move(receiver))); } -#if BUILDFLAG(CLANG_COVERAGE_INSIDE_SANDBOX) - void SetCoverageFile(base::File file) override { +#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) + void SetProfilingFile(base::File file) override { // TODO(crbug.com/985574) Remove Android check when possible. #if defined(OS_POSIX) && !defined(OS_ANDROID) // Take the file descriptor so that |file| does not close it.
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index 35eb5cde..af7b2f3 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -411,10 +411,10 @@ deps += [ "//third_party/fuchsia-sdk/sdk/pkg/fdio" ] } - if (use_clang_coverage_inside_sandbox) { + if (use_clang_profiling_inside_sandbox) { sources += [ - "coverage_utils.cc", - "coverage_utils.h", + "profiling_utils.cc", + "profiling_utils.h", ] } } @@ -476,8 +476,8 @@ if (is_linux || is_chromeos) { enabled_features += [ "supports_thread_priorities" ] } - if (use_clang_coverage_inside_sandbox) { - enabled_features += [ "clang_coverage_inside_sandbox" ] + if (use_clang_profiling_inside_sandbox) { + enabled_features += [ "clang_profiling_inside_sandbox" ] } import_dirs = [ "//mojo/services" ]
diff --git a/content/common/child_process.mojom b/content/common/child_process.mojom index b981e6a..d85e2810 100644 --- a/content/common/child_process.mojom +++ b/content/common/child_process.mojom
@@ -91,7 +91,8 @@ // depends on the process type and potentially on the Content embedder. BindReceiver(mojo_base.mojom.GenericPendingReceiver receiver); - // Sets the coverage file for the child process. - [EnableIf=clang_coverage_inside_sandbox] - SetCoverageFile(mojo_base.mojom.File file); + // Sets the profiling file for the child process. + // Used for the coverage builds. + [EnableIf=clang_profiling_inside_sandbox] + SetProfilingFile(mojo_base.mojom.File file); };
diff --git a/content/common/child_process_host_impl.cc b/content/common/child_process_host_impl.cc index 5543ebf..06f21f0 100644 --- a/content/common/child_process_host_impl.cc +++ b/content/common/child_process_host_impl.cc
@@ -7,7 +7,7 @@ #include <limits> #include "base/atomic_sequence_num.h" -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/command_line.h" #include "base/files/file.h" #include "base/files/file_path.h" @@ -42,8 +42,8 @@ #include "content/common/mac_helpers.h" #endif // OS_LINUX -#if BUILDFLAG(CLANG_COVERAGE_INSIDE_SANDBOX) -#include "content/common/coverage_utils.h" +#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) +#include "content/common/profiling_utils.h" #endif namespace { @@ -207,8 +207,8 @@ child_process_->SetIPCLoggingEnabled(enabled); #endif -#if BUILDFLAG(CLANG_COVERAGE_INSIDE_SANDBOX) - child_process_->SetCoverageFile(OpenCoverageFile()); +#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) + child_process_->SetProfilingFile(OpenProfilingFile()); #endif opening_channel_ = true;
diff --git a/content/common/common_param_traits_macros.h b/content/common/common_param_traits_macros.h index 0d2d07e..0701e83 100644 --- a/content/common/common_param_traits_macros.h +++ b/content/common/common_param_traits_macros.h
@@ -46,11 +46,11 @@ IPC_STRUCT_TRAITS_MEMBER(min_size_for_auto_resize) IPC_STRUCT_TRAITS_MEMBER(max_size_for_auto_resize) IPC_STRUCT_TRAITS_MEMBER(new_size) + IPC_STRUCT_TRAITS_MEMBER(visible_viewport_size) IPC_STRUCT_TRAITS_MEMBER(compositor_viewport_pixel_rect) IPC_STRUCT_TRAITS_MEMBER(browser_controls_params) IPC_STRUCT_TRAITS_MEMBER(scroll_focused_node_into_view) IPC_STRUCT_TRAITS_MEMBER(local_surface_id_allocation) - IPC_STRUCT_TRAITS_MEMBER(visible_viewport_size) IPC_STRUCT_TRAITS_MEMBER(is_fullscreen_granted) IPC_STRUCT_TRAITS_MEMBER(display_mode) IPC_STRUCT_TRAITS_MEMBER(capture_sequence_number)
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index 8b8cc90..4bdc050 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h
@@ -212,15 +212,16 @@ IPC_STRUCT_TRAITS_BEGIN(content::FrameVisualProperties) IPC_STRUCT_TRAITS_MEMBER(screen_info) IPC_STRUCT_TRAITS_MEMBER(auto_resize_enabled) + IPC_STRUCT_TRAITS_MEMBER(visible_viewport_size) IPC_STRUCT_TRAITS_MEMBER(min_size_for_auto_resize) IPC_STRUCT_TRAITS_MEMBER(max_size_for_auto_resize) - IPC_STRUCT_TRAITS_MEMBER(screen_space_rect) - IPC_STRUCT_TRAITS_MEMBER(local_frame_size) - IPC_STRUCT_TRAITS_MEMBER(compositor_viewport) IPC_STRUCT_TRAITS_MEMBER(capture_sequence_number) IPC_STRUCT_TRAITS_MEMBER(zoom_level) IPC_STRUCT_TRAITS_MEMBER(page_scale_factor) IPC_STRUCT_TRAITS_MEMBER(is_pinch_gesture_active) + IPC_STRUCT_TRAITS_MEMBER(screen_space_rect) + IPC_STRUCT_TRAITS_MEMBER(local_frame_size) + IPC_STRUCT_TRAITS_MEMBER(compositor_viewport) IPC_STRUCT_TRAITS_MEMBER(local_surface_id_allocation) IPC_STRUCT_TRAITS_END()
diff --git a/content/common/frame_visual_properties.h b/content/common/frame_visual_properties.h index 9659e81..24964d7 100644 --- a/content/common/frame_visual_properties.h +++ b/content/common/frame_visual_properties.h
@@ -22,35 +22,27 @@ FrameVisualProperties& operator=(const FrameVisualProperties& other); - // Information about the screen (dpi, depth, etc..). + // These fields are values from VisualProperties, see comments there for + // descriptions. They exist here to propagate from each RenderWidget to its + // child RenderWidgets. Here they are flowing from RenderWidget in a parent + // renderer process up to the RenderWidgetHost for a child RenderWidget in + // another renderer process. That RenderWidgetHost would then be responsible + // for passing it along to the child RenderWidget. ScreenInfo screen_info; - - // Whether or not blink should be in auto-resize mode. bool auto_resize_enabled = false; - - // The minimum size for Blink if auto-resize is enabled. + bool is_pinch_gesture_active = false; + uint32_t capture_sequence_number = 0u; + double zoom_level = 0; + float page_scale_factor = 1.f; + gfx::Size visible_viewport_size; gfx::Size min_size_for_auto_resize; - - // The maximum size for Blink if auto-resize is enabled. gfx::Size max_size_for_auto_resize; - gfx::Rect screen_space_rect; - - gfx::Size local_frame_size; - // The size of the compositor viewport, to match the sub-frame's surface. gfx::Rect compositor_viewport; - uint32_t capture_sequence_number = 0u; - - // This represents the page zoom level for a WebContents. - // (0 is the default value which results in 1.0 zoom factor.) - double zoom_level = 0; - - // Tracks the page-scale factor and whether the frame is currently in an - // active pinch-zoom gesture. - float page_scale_factor = 1.f; - bool is_pinch_gesture_active = false; + gfx::Rect screen_space_rect; + gfx::Size local_frame_size; // The time at which the viz::LocalSurfaceId used to submit this was // allocated.
diff --git a/content/common/page_messages.h b/content/common/page_messages.h index 24fa71dce..bab308c3 100644 --- a/content/common/page_messages.h +++ b/content/common/page_messages.h
@@ -33,11 +33,6 @@ IPC_MESSAGE_ROUTED1(PageMsg_AudioStateChanged, bool /* is_audio_playing */) -// Sent to renderers with remote main frames when page-related visual properties -// change. -IPC_MESSAGE_ROUTED1(PageMsg_UpdatePageVisualProperties, - gfx::Size /* VisualViewport size */) - // Sent to all renderers, instructing them to freeze or unfreeze all frames that // belongs to this page. IPC_MESSAGE_ROUTED1(PageMsg_SetPageFrozen, bool /* frozen */)
diff --git a/content/common/coverage_utils.cc b/content/common/profiling_utils.cc similarity index 91% rename from content/common/coverage_utils.cc rename to content/common/profiling_utils.cc index 609f503..48772eb 100644 --- a/content/common/coverage_utils.cc +++ b/content/common/profiling_utils.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/common/coverage_utils.h" +#include "content/common/profiling_utils.h" #include <memory> @@ -23,7 +23,7 @@ namespace content { -base::File OpenCoverageFile() { +base::File OpenProfilingFile() { base::ScopedAllowBlockingForTesting allows_blocking; std::unique_ptr<base::Environment> env(base::Environment::Create()); std::string prof_template; @@ -41,6 +41,8 @@ // sajjadm@ and liaoyuke@ experimentally determined that a size 4 pool works // well for the coverage builder. + // TODO(https://crbug.com/1059335): Check if this is an appropriate value for + // the PGO builds. int pool_index = base::RandInt(0, 3); std::string filename = base::StrCat( {"child_pool-", base::NumberToString(pool_index), ".profraw"});
diff --git a/content/common/coverage_utils.h b/content/common/profiling_utils.h similarity index 62% rename from content/common/coverage_utils.h rename to content/common/profiling_utils.h index 24d8270..f9e6e17 100644 --- a/content/common/coverage_utils.h +++ b/content/common/profiling_utils.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 CONTENT_COMMON_COVERAGE_UTILS_H_ -#define CONTENT_COMMON_COVERAGE_UTILS_H_ +#ifndef CONTENT_COMMON_PROFILING_UTILS_H_ +#define CONTENT_COMMON_PROFILING_UTILS_H_ #include <string> @@ -11,8 +11,8 @@ namespace content { -base::File OpenCoverageFile(); +base::File OpenProfilingFile(); } // namespace content -#endif // CONTENT_COMMON_COVERAGE_UTILS_H_ +#endif // CONTENT_COMMON_PROFILING_UTILS_H_
diff --git a/content/common/visual_properties.h b/content/common/visual_properties.h index 599c6b0f..82ffc7e 100644 --- a/content/common/visual_properties.h +++ b/content/common/visual_properties.h
@@ -72,9 +72,23 @@ // The size for the widget in DIPs. gfx::Size new_size; - // The rect of compositor's viewport in pixels. Note that this may differ in - // size from a ScaleToCeiledSize of |new_size| due to Android's keyboard or - // due to rounding particulars. + // The size of the area of the widget that is visible to the user, in DIPs. + // The visible area may be empty if the visible area does not intersect with + // the widget, for example in the case of a child frame that is entirely + // scrolled out of the main frame's viewport. It may also be smaller than the + // widget's size in |new_size| due to the UI hiding part of the widget, such + // as with an on-screen keyboard. + gfx::Size visible_viewport_size; + + // The rect of compositor's viewport in pixels. Note that for top level + // widgets this is roughly the DSF scaled new_size put into a rect. For child + // frame widgets it is a pixel-perfect bounds of the visible region of the + // widget. The size would be similar to visible_viewport_size, but in physical + // pixels and computed via very different means. + // TODO(danakj): It would be super nice to remove one of |new_size|, + // |visible_viewport_size| and |compositor_viewport_pixel_rect|. Their values + // overlap in purpose, creating a very confusing situation about which to use + // for what, and how they should relate or not. gfx::Rect compositor_viewport_pixel_rect; // Browser controls params such as top and bottom controls heights, whether @@ -88,11 +102,6 @@ // The local surface ID to use (if valid) and its allocation time. base::Optional<viz::LocalSurfaceIdAllocation> local_surface_id_allocation; - // The size of the visible viewport, which may be smaller than the view if the - // view is partially occluded (e.g. by a virtual keyboard). The size is in - // DPI-adjusted pixels. - gfx::Size visible_viewport_size; - // Indicates whether tab-initiated fullscreen was granted. bool is_fullscreen_granted = false;
diff --git a/content/public/browser/web_contents.cc b/content/public/browser/web_contents.cc index ce7342f6..d1d8ff8 100644 --- a/content/public/browser/web_contents.cc +++ b/content/public/browser/web_contents.cc
@@ -22,9 +22,6 @@ opener_render_frame_id(MSG_ROUTING_NONE), opener_suppressed(false), created_with_opener(false), - routing_id(MSG_ROUTING_NONE), - main_frame_routing_id(MSG_ROUTING_NONE), - main_frame_widget_routing_id(MSG_ROUTING_NONE), initially_hidden(false), guest_delegate(nullptr), context(nullptr),
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index f808d01..96d22f68 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -142,14 +142,6 @@ // (e.g., for blocked popups). bool created_with_opener; - // The routing ids of the RenderView, main RenderFrame, and the widget for - // the main RenderFrame. Either all routing IDs must be provided or all must - // be MSG_ROUTING_NONE to have WebContents make the assignment. If provided, - // these routing IDs are associated with |site_instance->GetProcess()|. - int32_t routing_id; - int32_t main_frame_routing_id; - int32_t main_frame_widget_routing_id; - // The name of the top-level frame of the new window. It is non-empty // when creating a named window (e.g. <a target="foo"> or // window.open('', 'bar')).
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 914cf95..7823050 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -2973,6 +2973,12 @@ render_view_->SetDeviceScaleFactor(use_zoom_for_dsf, device_scale_factor); } +void RenderFrameImpl::SetVisibleViewportSizeForChildLocalRootOnRenderView( + const gfx::Size& visible_viewport_size) { + DCHECK(frame_->Parent()); // Only called for child local roots. + render_view_->SetVisibleViewportSizeForChildLocalRoot(visible_viewport_size); +} + void RenderFrameImpl::AddMessageToConsole( blink::mojom::ConsoleMessageLevel level, const std::string& message) {
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 29c48c5..d34fa34 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -806,14 +806,23 @@ media::MediaPermission* GetMediaPermission(); // Proxies the call to set the zoom level over to the RenderViewImpl and - // returns its result. + // returns its result. Meant to be called by the |render_widget_| in order to + // get access to the RenderViewImpl. bool SetZoomLevelOnRenderView(double zoom_level); // Proxies the call to set the prefer compositing flag over to the - // RenderViewImpl. + // RenderViewImpl. Meant to be called by the |render_widget_| in order to get + // access to the RenderViewImpl. void SetPreferCompositingToLCDTextEnabledOnRenderView(bool prefer); // Proxies the call to set the device scale factor over to the RenderViewImpl. + // Meant to be called by the |render_widget_| in order to get access to the + // RenderViewImpl. void SetDeviceScaleFactorOnRenderView(bool use_zoom_for_dsf, float device_scale_factor); + // Proxies the call to set the visible viewport size over to the + // RenderViewImpl. Meant to be called by the |render_widget_| in order to get + // access to the RenderViewImpl. + void SetVisibleViewportSizeForChildLocalRootOnRenderView( + const gfx::Size& visible_viewport_size); // Sends the current frame's navigation state to the browser. void SendUpdateState();
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc index c0cc2ba..cad3bfce 100644 --- a/content/renderer/render_frame_impl_browsertest.cc +++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -215,31 +215,44 @@ // Verify a subframe RenderWidget properly processes its viewport being // resized. TEST_F(RenderFrameImplTest, FrameResize) { + // Make an update where the widget's size and the visible_viewport_size + // are not the same. VisualProperties visual_properties; - gfx::Size size(200, 200); - visual_properties.screen_info = ScreenInfo(); - visual_properties.new_size = size; - visual_properties.compositor_viewport_pixel_rect = gfx::Rect(size); - visual_properties.visible_viewport_size = size; - visual_properties.is_fullscreen_granted = false; + gfx::Size widget_size(400, 200); + gfx::Size visible_size(350, 170); + visual_properties.new_size = widget_size; + visual_properties.compositor_viewport_pixel_rect = gfx::Rect(widget_size); + visual_properties.visible_viewport_size = visible_size; + + RenderWidget* main_frame_widget = + GetMainRenderFrame()->GetLocalRootRenderWidget(); // The main frame's widget will receive the resize message before the // subframe's widget, and it will set the size for the WebView. - RenderWidget* main_frame_widget = - GetMainRenderFrame()->GetLocalRootRenderWidget(); - WidgetMsg_UpdateVisualProperties resize_message( - main_frame_widget->routing_id(), visual_properties); + { + WidgetMsg_UpdateVisualProperties resize_message( + main_frame_widget->routing_id(), visual_properties); + main_frame_widget->OnMessageReceived(resize_message); + } + // The main frame widget's size is the "widget size", not the visible viewport + // size, which is given to blink separately. + EXPECT_EQ(gfx::Size(view_->GetWebView()->MainFrameWidget()->Size()), + widget_size); + EXPECT_EQ(gfx::SizeF(view_->GetWebView()->VisualViewportSize()), + gfx::SizeF(visible_size)); + // The main frame doesn't change other local roots directly. + EXPECT_NE(gfx::Size(frame_widget()->GetWebWidget()->Size()), visible_size); - main_frame_widget->OnMessageReceived(resize_message); - EXPECT_EQ(view_->GetWebView()->MainFrameWidget()->Size(), - blink::WebSize(size)); - EXPECT_NE(frame_widget()->GetWebWidget()->Size(), blink::WebSize(size)); + // A subframe in the same process does not modify the WebView. + { + WidgetMsg_UpdateVisualProperties resize_message_subframe( + frame_widget()->routing_id(), visual_properties); + frame_widget()->OnMessageReceived(resize_message_subframe); + } + EXPECT_EQ(gfx::Size(frame_widget()->GetWebWidget()->Size()), widget_size); - // The subframe sets the size only for itself. - WidgetMsg_UpdateVisualProperties resize_message_subframe( - frame_widget()->routing_id(), visual_properties); - frame_widget()->OnMessageReceived(resize_message_subframe); - EXPECT_EQ(frame_widget()->GetWebWidget()->Size(), blink::WebSize(size)); + // A subframe in another process would use the |visible_viewport_size| as its + // size. } // Verify a subframe RenderWidget properly processes a WasShown message.
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc index cb2f95f..676217a 100644 --- a/content/renderer/render_frame_proxy.cc +++ b/content/renderer/render_frame_proxy.cc
@@ -304,6 +304,14 @@ SynchronizeVisualProperties(); } +void RenderFrameProxy::OnVisibleViewportSizeChanged( + const gfx::Size& visible_viewport_size) { + DCHECK(ancestor_render_widget_); + + pending_visual_properties_.visible_viewport_size = visible_viewport_size; + SynchronizeVisualProperties(); +} + void RenderFrameProxy::UpdateCaptureSequenceNumber( uint32_t capture_sequence_number) { DCHECK(ancestor_render_widget_); @@ -509,6 +517,8 @@ pending_visual_properties_.page_scale_factor || sent_visual_properties_->is_pinch_gesture_active != pending_visual_properties_.is_pinch_gesture_active || + sent_visual_properties_->visible_viewport_size != + pending_visual_properties_.visible_viewport_size || sent_visual_properties_->compositor_viewport != pending_visual_properties_.compositor_viewport || capture_sequence_number_changed;
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h index 708d49d..d202bf5 100644 --- a/content/renderer/render_frame_proxy.h +++ b/content/renderer/render_frame_proxy.h
@@ -127,21 +127,18 @@ const std::string& interface_name, mojo::ScopedInterfaceEndpointHandle handle) override; - // Out-of-process child frames receive a signal from RenderWidget when the - // ScreenInfo has changed. + // Propagate VisualProperties updates from a local root RenderWidget to the + // child RenderWidget represented by this proxy, which is hosted in another + // renderer frame tree. + // TODO(danakj): These should all be grouped into a single method, then we + // would only get one update per UpdateVisualProperties IPC received in the + // RenderWidget, and we would only need to send one update to the browser as + // a result. void OnScreenInfoChanged(const ScreenInfo& screen_info); - - // Out-of-process child frames receive a signal from RenderWidget when the - // zoom level has changed. void OnZoomLevelChanged(double zoom_level); - - // Out-of-process child frames receive a signal from RenderWidget when the - // page scale factor has changed, and/or a pinch-zoom gesture starts/ends. void OnPageScaleFactorChanged(float page_scale_factor, bool is_pinch_gesture_active); - - // Invoked by RenderWidget when a new capture sequence number was set, - // indicating that surfaces should be synchronized. + void OnVisibleViewportSizeChanged(const gfx::Size& visible_viewport_size); void UpdateCaptureSequenceNumber(uint32_t capture_sequence_number); // Pass replicated information, such as security origin, to this
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 1b137014..9c452f4 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -1086,8 +1086,10 @@ void RenderViewImpl::ResizeWebWidgetForWidget( const gfx::Size& widget_size, + const gfx::Size& visible_viewport_size, cc::BrowserControlsParams browser_controls_params) { - GetWebView()->ResizeWithBrowserControls(widget_size, browser_controls_params); + GetWebView()->ResizeWithBrowserControls(widget_size, visible_viewport_size, + browser_controls_params); } void RenderViewImpl::SetScreenMetricsEmulationParametersForWidget( @@ -1181,8 +1183,6 @@ IPC_MESSAGE_HANDLER(PageMsg_SetHistoryOffsetAndLength, OnSetHistoryOffsetAndLength) IPC_MESSAGE_HANDLER(PageMsg_AudioStateChanged, OnAudioStateChanged) - IPC_MESSAGE_HANDLER(PageMsg_UpdatePageVisualProperties, - OnUpdatePageVisualProperties) IPC_MESSAGE_HANDLER(PageMsg_SetPageFrozen, SetPageFrozen) IPC_MESSAGE_HANDLER(PageMsg_PutPageIntoBackForwardCache, PutPageIntoBackForwardCache) @@ -1447,6 +1447,23 @@ GetWebView()->SetDeviceScaleFactor(device_scale_factor); } +void RenderViewImpl::SetVisibleViewportSizeForChildLocalRoot( + const gfx::Size& visible_viewport_size) { + // The main frame is updated on a different path. If we're in the same frame + // tree as it, there's nothing to do for child local roots. + if (main_render_frame_) + return; + + // RenderWidgets in a RenderView's frame tree without a local main frame + // set the size of the WebView to be the |visible_viewport_size|, in order + // to limit compositing in (out of process) child frames to what is visible. + // + // Note that child frames in the same process/RenderView frame tree as the + // main frame do not do this in order to not clobber the source of truth in + // the main frame. + GetWebView()->Resize(visible_viewport_size); +} + void RenderViewImpl::PropagatePageZoomToNewlyAttachedFrame( bool use_zoom_for_dsf, float device_scale_factor) { @@ -1741,29 +1758,6 @@ /*initial_setting=*/false); } -void RenderViewImpl::OnUpdatePageVisualProperties( - const gfx::Size& viewport_size_for_blink) { - // TODO(https://crbug.com/998273): Handle visual_properties appropriately. - // Using this pathway to update the visual viewport should only happen for - // remote main frames. Local main frames will update the viewport size by - // RenderWidget calling RenderViewImpl::ResizeVisualViewport() directly. - // TODO(danakj): This should be part of VisualProperties and walk down the - // RenderWidget tree like other VisualProperties do, in order to set the - // value in each WebView holds a part of the local frame tree. - if (!main_render_frame_) - GetWebView()->Resize(viewport_size_for_blink); -} - -void RenderViewImpl::ResizeVisualViewportForWidget( - const gfx::Size& scaled_viewport_size) { - // This function is currently only called for local main frames. Once remote - // main frames no longer have a RenderWidget, they may also route through - // here via RenderViewImpl::OnUpdateLocalMainFramePageVisualProperties(). In - // that case, WebViewImpl will need to implement its Size() function based on - // something other than the widget size. - GetWebView()->ResizeVisualViewport(scaled_viewport_size); -} - void RenderViewImpl::SetPageFrozen(bool frozen) { if (GetWebView()) GetWebView()->SetPageFrozen(frozen);
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index ce65c24..78fa090 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -160,6 +160,13 @@ // Passes along the device scale factor to the WebView. void SetDeviceScaleFactor(bool use_zoom_for_dsf, float device_scale_factor); + // Passes along the visible viewport size to the WebView, for child local + // roots when there is no local main frame present. When a local main frame + // exists in this renderer's frame tree, its value should persist and this + // method does nothing. + void SetVisibleViewportSizeForChildLocalRoot( + const gfx::Size& visible_viewport_size); + // Passes along the page zoom to the WebView to set it on a newly attached // LocalFrame. void PropagatePageZoomToNewlyAttachedFrame(bool use_zoom_for_dsf, @@ -374,12 +381,11 @@ void DidCompletePageScaleAnimationForWidget() override; void ResizeWebWidgetForWidget( const gfx::Size& widget_size, + const gfx::Size& visible_viewport_size, cc::BrowserControlsParams browser_controls_params) override; void SetScreenMetricsEmulationParametersForWidget( bool enabled, const blink::WebDeviceEmulationParams& params) override; - void ResizeVisualViewportForWidget( - const gfx::Size& scaled_viewport_size) override; // Old WebLocalFrameClient implementations // ---------------------------------------- @@ -417,8 +423,6 @@ // Page message handlers ----------------------------------------------------- void OnPageVisibilityChanged(PageVisibilityState visibility_state); - void OnUpdateScreenInfo(const ScreenInfo& screen_info); - void OnUpdatePageVisualProperties(const gfx::Size& visible_viewport_size); void SetPageFrozen(bool frozen); void PutPageIntoBackForwardCache(); void RestorePageFromBackForwardCache(base::TimeTicks navigation_start);
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 09e791f..2370f1c 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -661,6 +661,61 @@ const VisualProperties& visual_properties_from_browser) { TRACE_EVENT0("renderer", "RenderWidget::OnUpdateVisualProperties"); + // UpdateVisualProperties is used to receive properties from the browser + // process for this RenderWidget. There are roughly 4 types of + // VisualProperties. + // TODO(danakj): Splitting these 4 types of properties apart and making them + // more explicit could be super useful to understanding this code. + // 1. Unique to each RenderWidget. Computed by the RenderWidgetHost and passed + // to the RenderWidget which consumes it here. + // Example: new_size. + // 2. Global properties, which are given to each RenderWidget (to maintain + // the requirement that a RenderWidget is updated atomically). These + // properties are usually the same for every RenderWidget, except when + // device emulation changes them in the main frame RenderWidget only. + // Example: screen_info. + // 3. Computed in the renderer of the main frame RenderWidget (in blink + // usually). Passed down through the waterfall dance to child frame + // RenderWidgets. Here that step is performed by passing the value along + // to all RenderFrameProxy objects that are below this RenderWidgets in the + // frame tree. The main frame (top level) RenderWidget ignores this value + // from its RenderWidgetHost since it is controlled in the renderer. Child + // frame RenderWidgets consume the value from their RenderWidgetHost. + // Example: page_scale_factor. + // 4. Computed independently in the renderer for each RenderWidget (in blink + // usually). Passed down from the parent to the child RenderWidgets through + // the waterfall dance, but the value only travels one step - the child + // frame RenderWidget would compute values for grandchild RenderWidgets + // independently. Here the value is passed to child frame RenderWidgets by + // passing the value along to all RenderFrameProxy objects that are below + // this RenderWidget in the frame tree. Each RenderWidget consumes this + // value when it is received from its RenderWidgetHost. + // Example: compositor_viewport_pixel_rect. + // For each of these properties: + // If the RenderView/WebView also knows these properties, each RenderWidget + // will pass them along to the RenderView as it receives it, even if there + // are multiple RenderWidgets related to the same RenderView. + // However when the main frame in the renderer is the source of truth, + // then child widgets must not clobber that value! In all cases child frames + // do not need to update state in the RenderView when a local main frame is + // present as it always sets the value first. + // TODO(danakj): This does create a race if there are multiple + // UpdateVisualProperties updates flowing through the RenderWidget tree at + // the same time, and it seems that only one RenderWidget for each + // RenderView should be responsible for this update. + // + // This operation is done by going through RenderFrameImpl to pass the value + // to the RenderViewImpl. While this class does not use RenderViewImpl + // directly, it speaks through the RenderFrameImpl::*OnRenderView() methods. + // TODO(danakj): A more explicit API to give values from here to RenderView + // and/or WebView would be nice. Also a more explicit API to give values to + // the RenderFrameProxy in one go, instead of setting each property + // independently, causing an update IPC from the RenderFrameProxy for each + // one. + // + // See also: + // https://docs.google.com/document/d/1G_fR1D_0c1yke8CqDMddoKrDGr3gy5t_ImEH4hKNIII/edit# + VisualProperties visual_properties = visual_properties_from_browser; // Web tests can override the device scale factor in the renderer. if (device_scale_factor_for_testing_) { @@ -808,18 +863,18 @@ // order to send IPCs that query and change compositing state. So // ResizeWebWidget() must come after this call, as it runs the entire // document lifecycle. - // - // TODO(danakj): Only the top-most RenderWidget per RenderView should - // be responsible for setting values onto the RenderView. render_frame->SetPreferCompositingToLCDTextEnabledOnRenderView( ComputePreferCompositingToLCDText( compositor_deps_, screen_info_.device_scale_factor)); } + // Store this even when auto-resizing, it is the size of the full viewport + // used for clipping, and this value is propagated down the RenderWidget + // hierarchy via the VisualProperties waterfall. + visible_viewport_size_ = visual_properties.visible_viewport_size; + if (!auto_resize_mode_) { display_mode_ = visual_properties.display_mode; - - visible_viewport_size_ = visual_properties.visible_viewport_size; size_ = visual_properties.new_size; ResizeWebWidget(); } @@ -865,6 +920,11 @@ if (old_visible_viewport_size != visible_viewport_size_) { for (auto& render_frame : render_frames_) render_frame.ResetHasScrolledFocusedEditableIntoView(); + + // Propagate changes down to child local root RenderWidgets and + // BrowserPlugins in other frame trees/processes. + for (auto& observer : render_frame_proxies_) + observer.OnVisibleViewportSizeChanged(visible_viewport_size_); } // TODO(crbug.com/939118): ScrollFocusedNodeIntoViewForWidget does not work // when the focused node is inside an OOPIF. This code path where @@ -939,8 +999,6 @@ RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(GetFrameWidget()->LocalRoot()); - // TODO(danakj): Only the top-most RenderWidget per RenderView should be - // responsible for setting values onto the RenderView. bool zoom_level_changed = render_frame->SetZoomLevelOnRenderView(zoom_level); if (zoom_level_changed) { // Hide popups when the zoom changes. @@ -951,6 +1009,7 @@ // Propagate changes down to child local root RenderWidgets and // BrowserPlugins in other frame trees/processes. + zoom_level_ = zoom_level; for (auto& observer : render_frame_proxies_) observer.OnZoomLevelChanged(zoom_level); } @@ -1511,27 +1570,37 @@ size_, GetOriginalScreenInfo().device_scale_factor); } - if (delegate()) { - // The visual viewport size given to blink is scaled by the (non-emulated, - // see https://crbug.com/819903) device scale factor (if UseZoomForDSF is - // enabled). - gfx::Size visible_viewport_size_for_blink; - if (!compositor_deps_->IsUseZoomForDSFEnabled()) { - visible_viewport_size_for_blink = visible_viewport_size_; - } else { - visible_viewport_size_for_blink = gfx::ScaleToCeiledSize( - visible_viewport_size_, GetOriginalScreenInfo().device_scale_factor); - } + // The |visible_viewport_size| given to blink is scaled by the (non-emulated, + // see https://crbug.com/819903) device scale factor (if UseZoomForDSF is + // enabled). + gfx::Size visible_viewport_size_for_blink; + if (!compositor_deps_->IsUseZoomForDSFEnabled()) { + visible_viewport_size_for_blink = visible_viewport_size_; + } else { + visible_viewport_size_for_blink = gfx::ScaleToCeiledSize( + visible_viewport_size_, GetOriginalScreenInfo().device_scale_factor); + } + if (delegate()) { // When associated with a RenderView, the RenderView is in control of the // main frame's size, because it includes other factors for top and bottom // controls. delegate()->ResizeWebWidgetForWidget(size_for_blink, + visible_viewport_size_for_blink, browser_controls_params_); - delegate()->ResizeVisualViewportForWidget(visible_viewport_size_for_blink); } else { - // When not associated with a RenderView, the RenderWidget is in control of - // the frame's (or other type of widget's) size. + // Child frames set the |visible_viewport_size| on the RenderView/WebView to + // limit the size blink tries to composite when the widget is not visible, + // such as when it is scrolled out of the main frame's view. + if (for_frame()) { + RenderFrameImpl* render_frame = + RenderFrameImpl::FromWebFrame(GetFrameWidget()->LocalRoot()); + render_frame->SetVisibleViewportSizeForChildLocalRootOnRenderView( + visible_viewport_size_for_blink); + } + + // For child frame widgets, popups, and pepper, the RenderWidget is in + // control of the WebWidget's size. GetWebWidget()->Resize(size_for_blink); } } @@ -2115,9 +2184,6 @@ // default value once we get to OnSynchronizeVisualProperties. Thus we // call into blink unconditionally and let it early out if it's already // set. - // - // TODO(danakj): Only the top-most RenderWidget per RenderView should - // be responsible for setting values onto the RenderView. render_frame->SetDeviceScaleFactorOnRenderView( compositor_deps_->IsUseZoomForDSFEnabled(), screen_info_.device_scale_factor); @@ -3374,12 +3440,16 @@ void RenderWidget::RegisterRenderFrameProxy(RenderFrameProxy* proxy) { render_frame_proxies_.AddObserver(proxy); - // Page scale factor is propagated down the RenderWidget tree (across - // frame trees). A new RenderFrameProxy means there is a new child - // RenderWidget in another frame tree. In order for it to hear about - // the page scale factor we pass along the last seen value here. + + // These properties are propagated down the RenderWidget tree through + // the RenderFrameProxy (see explanation in OnUpdateVisualProperties()). + // When a new RenderFrameProxy is added, we propagate them immediately. + proxy->OnPageScaleFactorChanged(page_scale_factor_from_mainframe_, is_pinch_gesture_active_from_mainframe_); + proxy->OnScreenInfoChanged(GetOriginalScreenInfo()); + proxy->OnZoomLevelChanged(zoom_level_); + proxy->OnVisibleViewportSizeChanged(visible_viewport_size_); } void RenderWidget::UnregisterRenderFrameProxy(RenderFrameProxy* proxy) {
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index ed595b5..60b849ac 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h
@@ -873,6 +873,13 @@ // The size of the visible viewport in pixels. gfx::Size visible_viewport_size_; + // Stores the zoom level to propagate to new child RenderWidgets. Initialized + // to 0 to match the value in RenderViewImpl, but this will be the value being + // propagated down the RenderWidget tree, whereas the value in RenderViewImpl + // is derived from these as RenderWidgets update their corresponding + // RenderViewImpls. + double zoom_level_ = 0; + // Whether the WebWidget is in auto resize mode, which is used for example // by extension popups. bool auto_resize_mode_ = false; @@ -976,8 +983,12 @@ scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue_; - // Lists of RenderFrameProxy objects that need to be notified of - // compositing-related events (e.g. DidCommitCompositorFrame). + // Lists of RenderFrameProxy objects for which this RenderWidget is their + // local root. Each of these represents a child local root RenderWidget in + // another RenderView frame tree. For values that are propagated from + // a parent RenderWidget to its children, they are plumbed through the + // RenderFrameProxys in this list, which bounce those values through the + // browser to the child RenderWidget in the correct process. base::ObserverList<RenderFrameProxy>::Unchecked render_frame_proxies_; // A list of RenderFrames associated with this RenderWidget. Notifications
diff --git a/content/renderer/render_widget_delegate.h b/content/renderer/render_widget_delegate.h index 85da7fe..bd7d362 100644 --- a/content/renderer/render_widget_delegate.h +++ b/content/renderer/render_widget_delegate.h
@@ -70,6 +70,7 @@ // happens. virtual void ResizeWebWidgetForWidget( const gfx::Size& size, + const gfx::Size& visible_viewport_size, cc::BrowserControlsParams browser_controls_params) = 0; // Called when RenderWidget services RenderWidgetScreenMetricsEmulatorDelegate @@ -77,11 +78,6 @@ virtual void SetScreenMetricsEmulationParametersForWidget( bool enabled, const blink::WebDeviceEmulationParams& params) = 0; - - // Called when the VisualViewport needs to be updated. Expects coordinates - // scaled to account for DeviceScaleFactor. - virtual void ResizeVisualViewportForWidget( - const gfx::Size& scaled_viewport_size) = 0; }; } // namespace content
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc index a5378e32..17d1ba6 100644 --- a/content/renderer/render_widget_unittest.cc +++ b/content/renderer/render_widget_unittest.cc
@@ -474,12 +474,12 @@ void DidReceiveSetFocusEventForWidget() override {} void DidCommitCompositorFrameForWidget() override {} void DidCompletePageScaleAnimationForWidget() override {} - void ResizeWebWidgetForWidget(const gfx::Size& size, + void ResizeWebWidgetForWidget(const gfx::Size& main_frame_widget_size, + const gfx::Size& visible_viewport_size, cc::BrowserControlsParams) override {} void SetScreenMetricsEmulationParametersForWidget( bool enabled, const blink::WebDeviceEmulationParams& params) override {} - void ResizeVisualViewportForWidget(const gfx::Size& viewport_size) override {} }; // Tests that the value of VisualProperties::is_pinch_gesture_active is
diff --git a/content/shell/android/BUILD.gn b/content/shell/android/BUILD.gn index a7d3937..68235ab6 100644 --- a/content/shell/android/BUILD.gn +++ b/content/shell/android/BUILD.gn
@@ -245,106 +245,6 @@ ] } -if (current_cpu != "x64") { - chromium_linker_test_manifest = - "$target_gen_dir/linker_test_apk/AndroidManifest.xml" - - jinja_template("chromium_linker_test_manifest") { - testonly = true - input = "linker_test_apk/AndroidManifest.xml.jinja2" - output = chromium_linker_test_manifest - } - - android_resources("linker_resources") { - testonly = true - resource_dirs = [ "linker_test_apk/res" ] - android_manifest = chromium_linker_test_manifest - android_manifest_dep = ":chromium_linker_test_manifest" - } - - _linker_test_apk_target_name = "chromium_linker_test_apk__apk" - _linker_test_apk_test_runner_target_name = - "chromium_linker_test_apk__test_runner_script" - _linker_test_jni_registration_header = - "$target_gen_dir/linker_test_apk/linker_test_jni_registration.h" - - android_apk(_linker_test_apk_target_name) { - testonly = true - deps = [ - ":content_shell_assets", - ":content_shell_java", - ":linker_resources", - "//base:base_java", - "//base:jni_java", - "//content/public/android:content_java", - "//ui/android:ui_java", - ] - android_manifest = chromium_linker_test_manifest - android_manifest_dep = ":chromium_linker_test_manifest" - apk_name = "ChromiumLinkerTest" - shared_libraries = [ ":linker_test" ] - use_chromium_linker = true - enable_chromium_linker_tests = true - jni_registration_header = _linker_test_jni_registration_header - sources = [ - "linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java", - "linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java", - "linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java", - ] - annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] - processor_args_javac = [ skip_gen_jni_arg ] - } - - test_runner_script(_linker_test_apk_test_runner_target_name) { - test_name = "chromium_linker_test_apk" - test_type = "linker" - apk_target = ":$_linker_test_apk_target_name" - ignore_all_data_deps = true - } - - group("chromium_linker_test_apk") { - testonly = true - deps = [ - ":$_linker_test_apk_target_name", - ":$_linker_test_apk_test_runner_target_name", - ] - } - - shared_library("linker_test") { - testonly = true - sources = [ - "linker_test_apk/chromium_linker_test_android.cc", - "linker_test_apk/chromium_linker_test_linker_tests.cc", - _linker_test_jni_registration_header, - ] - - deps = [ - ":${_linker_test_apk_target_name}__final_jni", - ":linker_test_jni_headers", - "//content/shell:content_shell_lib", - - # Required to include "content/public/browser/android/compositor.h" - # in chromium_linker_test_android.cc :-( - "//skia", - "//third_party/re2", - ] - - # Explicit dependency required for JNI registration to be able to - # find the native side functions. - if (is_component_build) { - deps += [ - "//device/gamepad", - "//media/midi", - ] - } - } - - generate_jni("linker_test_jni_headers") { - testonly = true - sources = [ "linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java" ] - } -} - android_library("content_shell_browsertests_java") { testonly = true deps = [
diff --git a/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2 b/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2 deleted file mode 100644 index 834e677..0000000 --- a/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2 +++ /dev/null
@@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- Copyright 2013 The Chromium Authors. All rights reserved. - - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. - --> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="org.chromium.chromium_linker_test_apk"> - - <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> - <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> - <uses-permission android:name="android.permission.CAMERA" /> - <uses-permission android:name="android.permission.INTERNET"/> - <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> - <uses-permission android:name="android.permission.RECORD_AUDIO"/> - <uses-permission android:name="android.permission.VIBRATE"/> - <uses-permission android:name="android.permission.WAKE_LOCK"/> - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> - - <application android:name="ChromiumLinkerTestApplication" - android:label="ChromiumLinkerTest"> - <activity android:name="ChromiumLinkerTestActivity" - android:launchMode="singleTask" - android:theme="@android:style/Theme.Holo.Light.NoActionBar" - android:configChanges="orientation|keyboardHidden|keyboard|screenSize" - android:hardwareAccelerated="true"> - <intent-filter> - <action android:name="android.intent.action.MAIN"/> - <category android:name="android.intent.category.LAUNCHER"/> - </intent-filter> - </activity> - <!-- The following service entries exist in order to allow us to - start more than one sandboxed process. --> - - <!-- NOTE: If you change the values of "android:process" for any of the below services, - you also need to update kHelperProcessExecutableName in chrome_constants.cc. --> - {% set num_sandboxed_services = 40 %} - <meta-data android:name="org.chromium.content.browser.NUM_SANDBOXED_SERVICES" - android:value="{{ num_sandboxed_services }}"/> - {% for i in range(num_sandboxed_services) %} - <service android:name="org.chromium.content.app.SandboxedProcessService{{ i }}" - android:process=":sandboxed_process{{ i }}" - android:isolatedProcess="true" - android:exported="false" /> - {% endfor %} - - {% set num_privileged_services = 5 %} - <meta-data android:name="org.chromium.content.browser.NUM_PRIVILEGED_SERVICES" - android:value="{{ num_privileged_services }}"/> - {% for i in range(num_privileged_services) %} - <service android:name="org.chromium.content.app.PrivilegedProcessService{{ i }}" - android:process=":privileged_process{{ i }}" - android:isolatedProcess="false" - android:exported="false" /> - {% endfor %} - </application> -</manifest>
diff --git a/content/shell/android/linker_test_apk/chromium_linker_test_android.cc b/content/shell/android/linker_test_apk/chromium_linker_test_android.cc deleted file mode 100644 index 300a15a3..0000000 --- a/content/shell/android/linker_test_apk/chromium_linker_test_android.cc +++ /dev/null
@@ -1,23 +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 "base/android/jni_android.h" -#include "base/android/library_loader/library_loader_hooks.h" -#include "base/bind.h" -#include "content/public/app/content_jni_onload.h" -#include "content/public/app/content_main.h" -#include "content/shell/android/linker_test_apk/linker_test_jni_registration.h" -#include "content/shell/app/shell_main_delegate.h" - -// This is called by the VM when the shared library is first loaded. -JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - base::android::InitVM(vm); - JNIEnv* env = base::android::AttachCurrentThread(); - if (!RegisterMainDexNatives(env) || !RegisterNonMainDexNatives(env) || - !content::android::OnJNIOnLoadInit()) { - return -1; - } - content::SetContentMainDelegate(new content::ShellMainDelegate()); - return JNI_VERSION_1_4; -}
diff --git a/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc b/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc deleted file mode 100644 index a949d30e..0000000 --- a/content/shell/android/linker_test_apk/chromium_linker_test_linker_tests.cc +++ /dev/null
@@ -1,195 +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. - -// This file implements the native methods of -// org.content.chromium.app.LinkerTests -// Unlike the content of linker_jni.cc, it is part of the content library and -// can thus use base/ and the C++ STL. - -#include <errno.h> -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <sys/mman.h> -#include <string> -#include <vector> - -#include "base/debug/proc_maps_linux.h" -#include "base/logging.h" -#include "base/strings/stringprintf.h" -#include "content/shell/android/linker_test_jni_headers/LinkerTests_jni.h" -#include "third_party/re2/src/re2/re2.h" - -using base::android::JavaParamRef; - -namespace content { - -namespace { - -using base::debug::MappedMemoryRegion; - -jboolean RunChecks(bool in_browser_process) { - // IMPORTANT NOTE: The Python test control script reads the logcat for - // lines like: - // BROWSER_LINKER_TEST: <status> - // RENDERER_LINKER_TEST: <status> - // - // Where <status> can be either SUCCESS or FAIL. Other lines starting - // with the same prefixes, but not using SUCCESS or FAIL are ignored. - const char* prefix = - in_browser_process ? "BROWSER_LINKER_TEST: " : "RENDERER_LINKER_TEST: "; - - // The RELRO section(s) will appear in /proc/self/maps as a mapped memory - // region for a file with a recognizable name. For the LegacyLinker the - // full name will be something like: - // - // "/dev/ashmem/RELRO:<libname> (deleted)" - // - // and for the ModernLinker, something like: - // - // "/data/data/org.chromium.chromium_linker_test_apk/ - // app_chromium_linker_test/RELRO:<libname> (deleted)" - // - // Where <libname> is the library name and '(deleted)' is actually - // added by the kernel to indicate there is no corresponding file - // on the filesystem. - // - // For regular builds, there is only one library, and thus one RELRO - // section, but for the component build, there are several libraries, - // each one with its own RELRO. - static const char kLegacyRelroSectionPattern[] = "/dev/ashmem/RELRO:.*"; - static const char kModernRelroSectionPattern[] = "/data/.*/RELRO:.*"; - - // Parse /proc/self/maps and builds a list of region mappings in this - // process. - std::string maps; - base::debug::ReadProcMaps(&maps); - if (maps.empty()) { - LOG(ERROR) << prefix << "FAIL Cannot parse /proc/self/maps"; - return false; - } - - std::vector<MappedMemoryRegion> regions; - base::debug::ParseProcMaps(maps, ®ions); - if (regions.empty()) { - LOG(ERROR) << prefix << "FAIL Cannot read memory mappings in this process"; - return false; - } - - const RE2 legacy_linker_re(kLegacyRelroSectionPattern); - const RE2 modern_linker_re(kModernRelroSectionPattern); - - int num_shared_relros = 0; - int num_bad_shared_relros = 0; - - for (size_t n = 0; n < regions.size(); ++n) { - MappedMemoryRegion& region = regions[n]; - - const std::string path = region.path; - const bool is_legacy_relro = re2::RE2::FullMatch(path, legacy_linker_re); - const bool is_modern_relro = re2::RE2::FullMatch(path, modern_linker_re); - - if (is_legacy_relro && is_modern_relro) { - LOG(ERROR) << prefix - << "FAIL RELRO cannot be both Legacy and Modern (test error)"; - return false; - } - - if (!is_legacy_relro && !is_modern_relro) { - // Ignore any mapping that isn't a shared RELRO. - continue; - } - - num_shared_relros++; - - void* region_start = reinterpret_cast<void*>(region.start); - void* region_end = reinterpret_cast<void*>(region.end); - - // Check that it is mapped read-only. - const uint8_t expected_flags = MappedMemoryRegion::READ; - const uint8_t expected_mask = MappedMemoryRegion::READ | - MappedMemoryRegion::WRITE | - MappedMemoryRegion::EXECUTE; - - uint8_t region_flags = region.permissions & expected_mask; - if (region_flags != expected_flags) { - LOG(ERROR) - << prefix - << base::StringPrintf( - "Shared RELRO section at %p-%p is not mapped read-only. " - "Protection flags are %d (%d expected)!", - region_start, - region_end, - region_flags, - expected_flags); - num_bad_shared_relros++; - continue; - } - - // Shared RELROs implemented by ModernLinker are not in ashmem. ModernLinker - // (via android_dlopen_ext()) maps everything with MAP_PRIVATE rather than - // MAP_SHARED. Remapping such a RELRO section read-write will therefore - // succeed, but it is not a problem. The memory copy-on-writes, and updates - // are not visible to either the mapped file or other processes mapping the - // same file. So... we skip the remap test for ModernLinker. - if (is_modern_relro) { - continue; - } - - // Check that trying to remap it read-write fails with EACCES - size_t region_size = region.end - region.start; - int ret = ::mprotect(region_start, region_size, PROT_READ | PROT_WRITE); - if (ret != -1) { - LOG(ERROR) - << prefix - << base::StringPrintf( - "Shared RELRO section at %p-%p could be remapped read-write!?", - region_start, - region_end); - num_bad_shared_relros++; - // Just in case. - ::mprotect(region_start, region_size, PROT_READ); - } else if (errno != EACCES) { - LOG(ERROR) << prefix << base::StringPrintf( - "Shared RELRO section at %p-%p failed " - "read-write mprotect with " - "unexpected error %d (EACCES:%d wanted): %s", - region_start, - region_end, - errno, - EACCES, - strerror(errno)); - num_bad_shared_relros++; - } - } - - VLOG(0) << prefix - << base::StringPrintf( - "There are %d shared RELRO sections in this process, of which " - "%d are bad", - num_shared_relros, num_bad_shared_relros); - - if (num_bad_shared_relros > 0) { - LOG(ERROR) << prefix << "FAIL Bad RELROs sections in this process"; - return false; - } - - if (num_shared_relros == 0) { - LOG(ERROR) << prefix - << "FAIL Missing shared RELRO sections in this process!"; - return false; - } - - VLOG(0) << prefix << "SUCCESS"; - return true; -} - -} // namespace - -jboolean JNI_LinkerTests_CheckForSharedRelros(JNIEnv* env, - jboolean in_browser_process) { - return RunChecks(in_browser_process); -} - -} // namespace content
diff --git a/content/shell/android/linker_test_apk/res/layout/test_activity.xml b/content/shell/android/linker_test_apk/res/layout/test_activity.xml deleted file mode 100644 index f018927..0000000 --- a/content/shell/android/linker_test_apk/res/layout/test_activity.xml +++ /dev/null
@@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- Copyright 2013 The Chromium Authors. All rights reserved. - - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. - --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical"> - <org.chromium.content_shell.ShellManager - android:id="@+id/shell_container" - android:layout_width="match_parent" - android:layout_height="match_parent" /> -</LinearLayout>
diff --git a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java deleted file mode 100644 index 2da5bfa..0000000 --- a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java +++ /dev/null
@@ -1,122 +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. - -package org.chromium.chromium_linker_test_apk; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; - -import org.chromium.base.Log; -import org.chromium.base.library_loader.LibraryLoader; -import org.chromium.base.library_loader.LibraryProcessType; -import org.chromium.base.library_loader.Linker; -import org.chromium.content_public.browser.BrowserStartupController; -import org.chromium.content_public.browser.WebContents; -import org.chromium.content_shell.Shell; -import org.chromium.content_shell.ShellManager; -import org.chromium.ui.base.ActivityWindowAndroid; - -/** - * Test activity used for verifying the different configuration options for the ContentLinker. - */ -public class ChromiumLinkerTestActivity extends Activity { - private static final String TAG = "LinkerTest"; - - private ShellManager mShellManager; - private ActivityWindowAndroid mWindowAndroid; - - @Override - public void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Setup the TestRunner class name. - Linker.setupForTesting(Linker.LINKER_IMPLEMENTATION_LEGACY, - "org.chromium.chromium_linker_test_apk.LinkerTests"); - - // Load the library in the browser process, this will also run the test - // runner in this process. - LibraryLoader.getInstance().ensureInitialized(); - - // Now, start a new renderer process by creating a new view. - // This will run the test runner in the renderer process. - - LayoutInflater inflater = - (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View view = inflater.inflate(R.layout.test_activity, null); - mShellManager = view.findViewById(R.id.shell_container); - mWindowAndroid = new ActivityWindowAndroid(this, false); - mShellManager.setWindow(mWindowAndroid); - - mShellManager.setStartupUrl("about:blank"); - - BrowserStartupController.getInstance().startBrowserProcessesAsync( - LibraryProcessType.PROCESS_BROWSER, true, false, - new BrowserStartupController.StartupCallback() { - @Override - public void onSuccess() { - finishInitialization(savedInstanceState); - } - - @Override - public void onFailure() { - initializationFailed(); - } - }); - - // TODO(digit): Ensure that after the content view is initialized, - // the program finishes(). - } - - private void finishInitialization(Bundle savedInstanceState) { - String shellUrl = ShellManager.DEFAULT_SHELL_URL; - mShellManager.launchShell(shellUrl); - } - - private void initializationFailed() { - Log.e(TAG, "ContentView initialization failed."); - finish(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mWindowAndroid.saveInstanceState(outState); - } - - @Override - protected void onStop() { - super.onStop(); - - WebContents webContents = getActiveWebContents(); - if (webContents != null) webContents.onHide(); - } - - @Override - protected void onStart() { - super.onStart(); - - WebContents webContents = getActiveWebContents(); - if (webContents != null) webContents.onHide(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - mWindowAndroid.onActivityResult(requestCode, resultCode, data); - } - - /** - * @return The {@link WebContents} owned by the currently visible {@link Shell} or null if - * one is not showing. - */ - public WebContents getActiveWebContents() { - if (mShellManager == null) return null; - Shell shell = mShellManager.getActiveShell(); - return shell != null ? shell.getWebContents() : null; - } -}
diff --git a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java deleted file mode 100644 index a646bf8..0000000 --- a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java +++ /dev/null
@@ -1,43 +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. - -package org.chromium.chromium_linker_test_apk; - -import android.app.Application; -import android.content.Context; - -import org.chromium.base.BuildConfig; -import org.chromium.base.ContextUtils; -import org.chromium.base.PathUtils; -import org.chromium.base.library_loader.LibraryLoader; -import org.chromium.base.library_loader.LibraryProcessType; -import org.chromium.base.multidex.ChromiumMultiDexInstaller; -import org.chromium.ui.base.ResourceBundle; - -/** - * Application for testing the Chromium Linker - */ -public class ChromiumLinkerTestApplication extends Application { - private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "chromium_linker_test"; - - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(base); - boolean isBrowserProcess = !ContextUtils.getProcessName().contains(":"); - LibraryLoader.getInstance().setLibraryProcessType(isBrowserProcess - ? LibraryProcessType.PROCESS_BROWSER - : LibraryProcessType.PROCESS_CHILD); - if (BuildConfig.IS_MULTIDEX_ENABLED) { - ChromiumMultiDexInstaller.install(this); - } - ContextUtils.initApplicationContext(this); - ResourceBundle.setNoAvailableLocalePaks(); - } - - @Override - public void onCreate() { - super.onCreate(); - PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX); - } -}
diff --git a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java deleted file mode 100644 index 0405afc8..0000000 --- a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/LinkerTests.java +++ /dev/null
@@ -1,32 +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. - -package org.chromium.chromium_linker_test_apk; - -import org.chromium.base.annotations.JNINamespace; -import org.chromium.base.annotations.NativeMethods; -import org.chromium.base.library_loader.Linker; - -/** - * A class that is only used in linker test APK to perform runtime checks - * in the current process. - */ -@JNINamespace("content") -public class LinkerTests implements Linker.TestRunner { - private static final String TAG = "LinkerTest"; - - public LinkerTests() {} - - @Override - public boolean runChecks(boolean isBrowserProcess) { - return LinkerTestsJni.get().checkForSharedRelros(isBrowserProcess); - } - - @NativeMethods - interface Natives { - // Check that there are shared RELRO sections in the current process, - // and that they are properly mapped read-only. Returns true on success. - boolean checkForSharedRelros(boolean isBrowserProcess); - } -}
diff --git a/docs/chromoting_android_hacking.md b/docs/chromoting_android_hacking.md index 0bae0f3..2d21bfb 100644 --- a/docs/chromoting_android_hacking.md +++ b/docs/chromoting_android_hacking.md
@@ -104,7 +104,6 @@ <classpathentry kind="src" path="content/shell/android/java/src"/> <classpathentry kind="src" path="content/shell/android/shell_apk/src"/> <classpathentry kind="src" path="content/shell/android/javatests/src"/> -<classpathentry kind="src" path="content/shell/android/linker_test_apk/src"/> <classpathentry kind="lib" path="third_party/android_sdk/public/platforms/android-27/data/layoutlib.jar"/> <classpathentry kind="lib" path="third_party/android_sdk/public/platforms/android-27/android.jar"/> <classpathentry kind="output" path="out/bin"/>
diff --git a/docs/fuchsia_build_instructions.md b/docs/fuchsia_build_instructions.md index 11bcc6c7..5c5d2ac 100644 --- a/docs/fuchsia_build_instructions.md +++ b/docs/fuchsia_build_instructions.md
@@ -190,6 +190,11 @@ ``` 3. Add users to the "kvm" group, and have them login again, to pick-up the new group. +```shell +$ sudo adduser <user> kvm +$ exit +[log in again] +``` ### Running test suites
diff --git a/gpu/command_buffer/common/shared_image_usage.h b/gpu/command_buffer/common/shared_image_usage.h index 76cdd80..9fef1ad 100644 --- a/gpu/command_buffer/common/shared_image_usage.h +++ b/gpu/command_buffer/common/shared_image_usage.h
@@ -35,6 +35,9 @@ // TODO(crbug.com/969114): This usage is currently not supported in GL/Vulkan // interop cases. SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE = 1 << 9, + // Image will be used in a platform specific API that requires a native buffer + // allocation. + SHARED_IMAGE_USAGE_NATIVE_BUFFER = 1 << 10, }; } // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc index c27839ce..994bb856 100644 --- a/gpu/command_buffer/service/shared_image_factory.cc +++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -386,6 +386,7 @@ bool share_between_gl_vulkan = gl_usage && vulkan_usage; bool using_interop_factory = share_between_gl_vulkan || using_dawn || share_between_gl_metal || + (usage & SHARED_IMAGE_USAGE_NATIVE_BUFFER) || (share_between_threads && vulkan_usage); // TODO(vasilyt): Android required AHB for overlays
diff --git a/gpu/ipc/service/gpu_watchdog_thread_v2.cc b/gpu/ipc/service/gpu_watchdog_thread_v2.cc index cfaa7b0..bdd9869 100644 --- a/gpu/ipc/service/gpu_watchdog_thread_v2.cc +++ b/gpu/ipc/service/gpu_watchdog_thread_v2.cc
@@ -741,6 +741,10 @@ // number to calculate the number of users who had already quit. RecordNumOfUsersWaitingWithExtraThreadTimeHistogram( count_of_more_gpu_thread_time_allowed_); + + // Used by GPU.WatchdogThread.WaitTime later + time_in_wait_for_full_thread_time_ = + count_of_more_gpu_thread_time_allowed_ * watchdog_timeout_; } } } @@ -761,6 +765,23 @@ GpuWatchdogTimeoutHistogram(GpuWatchdogTimeoutEvent::kProgressAfterWait); base::UmaHistogramExactLinear( "GPU.WatchdogThread.WaitTime.ProgressAfterWait", count, kMax); + +#if defined(OS_WIN) + // Add the time the GPU thread was given for the full thread time up to 60 + // seconds. GPU.WatchdogThread.WaitTime is essentially equal to + // GPU.WatchdogThread.WaitTime.ProgressAfterWait on non-Windows systems. + base::TimeDelta wait_time = base::TimeDelta::FromSeconds(count); + wait_time += time_in_wait_for_full_thread_time_; + + constexpr base::TimeDelta kMinTime = base::TimeDelta::FromSeconds(1); + constexpr base::TimeDelta kMaxTime = base::TimeDelta::FromSeconds(150); + constexpr int kBuckets = 50; + + // The time the GPU main thread takes to finish a task after a "hang" is + // dectedted. + base::UmaHistogramCustomTimes("GPU.WatchdogThread.WaitTime", wait_time, + kMinTime, kMaxTime, kBuckets); +#endif } } }
diff --git a/gpu/ipc/service/gpu_watchdog_thread_v2.h b/gpu/ipc/service/gpu_watchdog_thread_v2.h index ba51a10..6056afb 100644 --- a/gpu/ipc/service/gpu_watchdog_thread_v2.h +++ b/gpu/ipc/service/gpu_watchdog_thread_v2.h
@@ -168,6 +168,10 @@ // continue due to not enough thread time. int count_of_more_gpu_thread_time_allowed_ = 0; + // The total timeout, up to 60 seconds, the watchdog thread waits for the GPU + // main thread to get full thread time. + base::TimeDelta time_in_wait_for_full_thread_time_; + // After detecting GPU hang and continuing running through // OnGpuWatchdogTimeout for the max cycles, the GPU main thread still cannot // get the full thread time.
diff --git a/ios/chrome/app/tests_fake_hook.mm b/ios/chrome/app/tests_fake_hook.mm index a65067f9..27d3c5a 100644 --- a/ios/chrome/app/tests_fake_hook.mm +++ b/ios/chrome/app/tests_fake_hook.mm
@@ -28,6 +28,9 @@ bool DisableUpdateService() { return false; } +policy::ConfigurationPolicyProvider* GetOverriddenPlatformPolicyProvider() { + return nullptr; +} void SetUpTestsIfPresent() {} void RunTestsIfPresent() {}
diff --git a/ios/chrome/app/tests_hook.h b/ios/chrome/app/tests_hook.h index ab4ac8a..f6a939e 100644 --- a/ios/chrome/app/tests_hook.h +++ b/ios/chrome/app/tests_hook.h
@@ -5,6 +5,10 @@ #ifndef IOS_CHROME_APP_TESTS_HOOK_H_ #define IOS_CHROME_APP_TESTS_HOOK_H_ +namespace policy { +class ConfigurationPolicyProvider; +} + namespace tests_hook { // Returns true if app group access should be disabled as tests don't have the @@ -32,6 +36,10 @@ // infobar won't be shown during testing. bool DisableUpdateService(); +// Returns a policy provider that should be installed as the platform policy +// provider when testing. May return nullptr. +policy::ConfigurationPolicyProvider* GetOverriddenPlatformPolicyProvider(); + // Global integration tests setup. This is not used by EarlGrey-based // integration tests. void SetUpTestsIfPresent();
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn index 88312ac..7d1e209 100644 --- a/ios/chrome/browser/BUILD.gn +++ b/ios/chrome/browser/BUILD.gn
@@ -214,6 +214,7 @@ "//components/variations/field_trial_config", "//components/variations/service", "//components/version_info", + "//ios/chrome/app:tests_hook", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/browser_state:browser_state_impl", "//ios/chrome/browser/component_updater",
diff --git a/ios/chrome/browser/application_context_impl.cc b/ios/chrome/browser/application_context_impl.cc index 02b33e7..308339ab 100644 --- a/ios/chrome/browser/application_context_impl.cc +++ b/ios/chrome/browser/application_context_impl.cc
@@ -40,6 +40,7 @@ #include "components/update_client/configurator.h" #include "components/update_client/update_query_params.h" #include "components/variations/service/variations_service.h" +#include "ios/chrome/app/tests_hook.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.h" @@ -423,6 +424,15 @@ DCHECK(ui::ResourceBundle::HasSharedInstance()); browser_policy_connector_ = std::make_unique<BrowserPolicyConnectorIOS>( base::Bind(&BuildPolicyHandlerList)); + + // Install a mock platform policy provider, if running under EG2 and one + // is supplied. + policy::ConfigurationPolicyProvider* test_policy_provider = + tests_hook::GetOverriddenPlatformPolicyProvider(); + if (test_policy_provider) { + browser_policy_connector_->SetPolicyProviderForTesting( + test_policy_provider); + } } } return browser_policy_connector_.get();
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 8d07bbf..a2044d5e 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -457,7 +457,7 @@ autofill::features::kAutofillUseMobileLabelDisambiguation, kAutofillUseMobileLabelDisambiguationVariations, "AutofillUseMobileLabelDisambiguation")}, - {"enable-autofill-prune-suggestions", + {"autofill-prune-suggestions", flag_descriptions::kAutofillPruneSuggestionsName, flag_descriptions::kAutofillPruneSuggestionsDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(autofill::features::kAutofillPruneSuggestions)},
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.h b/ios/chrome/browser/overlays/overlay_presenter_impl.h index 8c20cff..5c4994ce 100644 --- a/ios/chrome/browser/overlays/overlay_presenter_impl.h +++ b/ios/chrome/browser/overlays/overlay_presenter_impl.h
@@ -130,6 +130,9 @@ override; void OverlayPresentationContextDidChangePresentationCapabilities( OverlayPresentationContext* presentation_context) override; + void OverlayPresentationContextDidMoveToWindow( + OverlayPresentationContext* presentation_context, + UIWindow* window) override; // WebStateListObserver: void WebStateInsertedAt(WebStateList* web_state_list,
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.mm b/ios/chrome/browser/overlays/overlay_presenter_impl.mm index 6bbd426..941a082 100644 --- a/ios/chrome/browser/overlays/overlay_presenter_impl.mm +++ b/ios/chrome/browser/overlays/overlay_presenter_impl.mm
@@ -201,12 +201,18 @@ if (!presentation_context_ || presentation_context_->IsShowingOverlayUI()) return; - // No presentation is necessary if there is no active reqeust or the context - // is unable to show it. + // No presentation is necessary if there is no active reqeust. OverlayRequest* request = GetActiveRequest(); - if (!request || !presentation_context_->CanShowUIForRequest(request)) + if (!request) return; + // Presentation cannot occur if the context is currently unable to show the UI + // for |request|. Attempt to prepare the presentation context for |request|. + if (!presentation_context_->CanShowUIForRequest(request)) { + presentation_context_->PrepareToShowOverlayUI(request); + return; + } + presenting_ = true; presented_request_ = request; @@ -407,6 +413,14 @@ PresentOverlayForActiveRequest(); } +void OverlayPresenterImpl::OverlayPresentationContextDidMoveToWindow( + OverlayPresentationContext* presentation_context, + UIWindow* window) { + DCHECK_EQ(presentation_context_, presentation_context); + if (!presenting_ && window) + PresentOverlayForActiveRequest(); +} + #pragma mark - WebStateListObserver void OverlayPresenterImpl::WebStateInsertedAt(WebStateList* web_state_list,
diff --git a/ios/chrome/browser/overlays/public/overlay_presentation_context.h b/ios/chrome/browser/overlays/public/overlay_presentation_context.h index 1162f7b..79b8a21 100644 --- a/ios/chrome/browser/overlays/public/overlay_presentation_context.h +++ b/ios/chrome/browser/overlays/public/overlay_presentation_context.h
@@ -50,6 +50,15 @@ // Whether overlay UI is currently shown in the context. virtual bool IsShowingOverlayUI() const = 0; + // Instructs the presentation context to prepare itself to show the overlay UI + // for |request|. If successful, updates the context's presentation + // capabilities to those required for |request|'s UI. Has no effect if the + // context is incapable of supporting |request|. For example, the context + // cannot support UIPresentationCapabilities::kPresented until it is added to + // a window (OverlayPresentationContextObserver can be used to detect window + // changes). + virtual void PrepareToShowOverlayUI(OverlayRequest* request) = 0; + // Called to show the overlay UI for |request|. |presentation_callback| must // be called when the UI is finished being presented. |dismissal_callback| // must be stored and called whenever the UI is finished being dismissed for
diff --git a/ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h b/ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h index 7023d92..618f20a 100644 --- a/ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h +++ b/ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h
@@ -5,6 +5,8 @@ #ifndef IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_OVERLAY_PRESENTATION_CONTEXT_OBSERVER_H_ #define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_OVERLAY_PRESENTATION_CONTEXT_OBSERVER_H_ +#import <UIKit/UIKit.h> + #include "base/observer_list_types.h" #import "ios/chrome/browser/overlays/public/overlay_presentation_context.h" @@ -22,6 +24,11 @@ // Called after |presentation_context|'s activation state changes. virtual void OverlayPresentationContextDidChangePresentationCapabilities( OverlayPresentationContext* presentation_context) {} + + // Called when |presentation_context| moves to |window|. + virtual void OverlayPresentationContextDidMoveToWindow( + OverlayPresentationContext* presentation_context, + UIWindow* window) {} }; #endif // IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_OVERLAY_PRESENTATION_CONTEXT_OBSERVER_H_
diff --git a/ios/chrome/browser/overlays/public/test_modality/BUILD.gn b/ios/chrome/browser/overlays/public/test_modality/BUILD.gn index ebdad47..7948c549 100644 --- a/ios/chrome/browser/overlays/public/test_modality/BUILD.gn +++ b/ios/chrome/browser/overlays/public/test_modality/BUILD.gn
@@ -9,6 +9,8 @@ "test_contained_overlay_request_config.mm", "test_presented_overlay_request_config.h", "test_presented_overlay_request_config.mm", + "test_resizing_presented_overlay_request_config.h", + "test_resizing_presented_overlay_request_config.mm", ] configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.h b/ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.h new file mode 100644 index 0000000..c52114b6 --- /dev/null +++ b/ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.h
@@ -0,0 +1,29 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_TEST_MODALITY_TEST_RESIZING_PRESENTED_OVERLAY_REQUEST_CONFIG_H_ +#define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_TEST_MODALITY_TEST_RESIZING_PRESENTED_OVERLAY_REQUEST_CONFIG_H_ + +#import <QuartzCore/QuartzCore.h> + +#include "ios/chrome/browser/overlays/public/overlay_request_config.h" + +// An OverlayRequestConfig to use in tests for presented UIViewControllers that +// resize their presentation container views. +class TestResizingPresentedOverlay + : public OverlayRequestConfig<TestResizingPresentedOverlay> { + public: + ~TestResizingPresentedOverlay() override; + + // The frame of the presented view in window coordinates. + const CGRect& frame() { return frame_; } + + private: + OVERLAY_USER_DATA_SETUP(TestResizingPresentedOverlay); + TestResizingPresentedOverlay(const CGRect& frame); + + const CGRect frame_; +}; + +#endif // IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_TEST_MODALITY_TEST_RESIZING_PRESENTED_OVERLAY_REQUEST_CONFIG_H_
diff --git a/ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.mm b/ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.mm new file mode 100644 index 0000000..390b4542 --- /dev/null +++ b/ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.mm
@@ -0,0 +1,16 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +OVERLAY_USER_DATA_SETUP_IMPL(TestResizingPresentedOverlay); + +TestResizingPresentedOverlay::TestResizingPresentedOverlay(const CGRect& frame) + : frame_(frame) {} + +TestResizingPresentedOverlay::~TestResizingPresentedOverlay() = default;
diff --git a/ios/chrome/browser/overlays/test/BUILD.gn b/ios/chrome/browser/overlays/test/BUILD.gn index 16756cc..35d7c785 100644 --- a/ios/chrome/browser/overlays/test/BUILD.gn +++ b/ios/chrome/browser/overlays/test/BUILD.gn
@@ -5,8 +5,8 @@ source_set("test") { testonly = true sources = [ - "fake_overlay_presentation_context.cc", "fake_overlay_presentation_context.h", + "fake_overlay_presentation_context.mm", "fake_overlay_request_callback_installer.cc", "fake_overlay_request_callback_installer.h", "fake_overlay_request_cancel_handler.cc",
diff --git a/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h b/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h index a14bb13..9c9cdd6 100644 --- a/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h +++ b/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h
@@ -48,6 +48,7 @@ UIPresentationCapabilities capabilities) const override; bool CanShowUIForRequest(OverlayRequest* request) const override; bool IsShowingOverlayUI() const override; + void PrepareToShowOverlayUI(OverlayRequest* request) override; void ShowOverlayUI(OverlayRequest* request, OverlayPresentationCallback presentation_callback, OverlayDismissalCallback dismissal_callback) override;
diff --git a/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.cc b/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.mm similarity index 93% rename from ios/chrome/browser/overlays/test/fake_overlay_presentation_context.cc rename to ios/chrome/browser/overlays/test/fake_overlay_presentation_context.mm index 55053f3..f718227b 100644 --- a/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.cc +++ b/ios/chrome/browser/overlays/test/fake_overlay_presentation_context.mm
@@ -9,6 +9,10 @@ #include "ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h" #include "ios/chrome/browser/overlays/public/overlay_request_queue.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + FakeOverlayPresentationContext::FakeOverlayPresentationContext() = default; FakeOverlayPresentationContext::~FakeOverlayPresentationContext() = default; @@ -88,6 +92,9 @@ return false; } +void FakeOverlayPresentationContext::PrepareToShowOverlayUI( + OverlayRequest* request) {} + void FakeOverlayPresentationContext::ShowOverlayUI( OverlayRequest* request, OverlayPresentationCallback presentation_callback, @@ -102,8 +109,7 @@ SimulateDismissalForRequest(request, OverlayDismissalReason::kHiding); } -void FakeOverlayPresentationContext::CancelOverlayUI( - OverlayRequest* request) { +void FakeOverlayPresentationContext::CancelOverlayUI(OverlayRequest* request) { FakeUIState& state = states_[request]; if (state.presentation_state == PresentationState::kPresented) { SimulateDismissalForRequest(request, OverlayDismissalReason::kCancellation);
diff --git a/ios/chrome/browser/policy/BUILD.gn b/ios/chrome/browser/policy/BUILD.gn index e0abaedc..914ff53 100644 --- a/ios/chrome/browser/policy/BUILD.gn +++ b/ios/chrome/browser/policy/BUILD.gn
@@ -46,3 +46,61 @@ "//ios/chrome/browser:utils", ] } + +source_set("test_support") { + testonly = true + sources = [ + "test_platform_policy_provider.cc", + "test_platform_policy_provider.h", + ] + + deps = [ "//base" ] + + public_deps = [ "//components/policy/core/common:test_support" ] + + configs += [ "//build/config/compiler:enable_arc" ] +} + +source_set("eg2_tests") { + defines = [ "CHROME_EARL_GREY_2" ] + configs += [ + "//build/config/compiler:enable_arc", + "//build/config/ios:xctest_config", + ] + testonly = true + + sources = [ + "policy_egtest.mm", + "policy_egtest_app_interface.h", + ] + + deps = [ + "//base", + "//components/strings", + "//ios/chrome/browser:utils", + "//ios/chrome/test/earl_grey:eg_test_support+eg2", + "//ios/testing/earl_grey:eg_test_support+eg2", + "//ios/third_party/earl_grey2:test_lib", + "//ui/base", + ] + + libs = [ "UIKit.framework" ] +} + +source_set("eg_app_support+eg2") { + defines = [ "CHROME_EARL_GREY_2" ] + configs += [ "//build/config/compiler:enable_arc" ] + testonly = true + sources = [ + "policy_egtest_app_interface.h", + "policy_egtest_app_interface.mm", + ] + deps = [ + ":policy", + "//base", + "//components/policy/core/browser", + "//components/policy/core/common", + "//ios/chrome/browser", + ] + libs = [ "Foundation.framework" ] +}
diff --git a/ios/chrome/browser/policy/policy_egtest.mm b/ios/chrome/browser/policy/policy_egtest.mm new file mode 100644 index 0000000..c858a79c --- /dev/null +++ b/ios/chrome/browser/policy/policy_egtest.mm
@@ -0,0 +1,123 @@ +// Copyright 2020 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 "ios/testing/earl_grey/earl_grey_test.h" + +#include <memory> + +#include "base/json/json_string_value_serializer.h" +#include "base/strings/sys_string_conversions.h" +#include "components/strings/grit/components_strings.h" +#include "ios/chrome/browser/chrome_switches.h" +#import "ios/chrome/browser/policy/policy_egtest_app_interface.h" +#include "ios/chrome/test/earl_grey/chrome_earl_grey.h" +#include "ios/chrome/test/earl_grey/chrome_test_case.h" +#include "ios/testing/earl_grey/app_launch_configuration.h" +#include "ios/testing/earl_grey/app_launch_manager.h" +#include "ui/base/l10n/l10n_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(PolicyEGTestAppInterface) + +namespace { + +// Returns the value of a given policy, looked up in the current platform policy +// provider. +std::unique_ptr<base::Value> GetPlatformPolicy(const std::string& key) { + std::string json_representation = + base::SysNSStringToUTF8([PolicyEGTestAppInterface + valueForPlatformPolicy:base::SysUTF8ToNSString(key)]); + JSONStringValueDeserializer deserializer(json_representation); + return deserializer.Deserialize(/*error_code=*/nullptr, + /*error_message=*/nullptr); +} + +} // namespace + +// Test case to verify that enterprise policies are set and respected. +@interface PolicyTestCase : ChromeTestCase +@end + +@implementation PolicyTestCase + +- (AppLaunchConfiguration)appConfigurationForTestCase { + // Use commandline args to insert fake policy data into NSUserDefaults. To the + // app, this policy data will appear under the + // "com.apple.configuration.managed" key. + AppLaunchConfiguration config; + config.additional_args.push_back(std::string("--") + + switches::kEnableEnterprisePolicy); + config.relaunch_policy = NoForceRelaunchAndResetState; + return config; +} + +// Tests that about:policy is available. +- (void)testAboutPolicy { + [ChromeEarlGrey loadURL:GURL("chrome://policy")]; + [ChromeEarlGrey waitForWebStateContainingText:l10n_util::GetStringUTF8( + IDS_POLICY_SHOW_UNSET)]; +} + +@end + +// Test case that uses the production platform policy provider. +@interface PolicyPlatformProviderTestCase : ChromeTestCase +@end + +@implementation PolicyPlatformProviderTestCase + +- (AppLaunchConfiguration)appConfigurationForTestCase { + AppLaunchConfiguration config; + config.additional_args.push_back(std::string("--") + + switches::kEnableEnterprisePolicy); + + // Commandline flags that start with a single "-" are automatically added to + // the NSArgumentDomain in NSUserDefaults. Set fake policy data that can be + // read by the production platform policy provider. + config.additional_args.push_back("-com.apple.configuration.managed"); + config.additional_args.push_back("{ChromePolicy={" + "DefaultSearchProviderName=Test;" + "NotARegisteredPolicy=Unknown;" + "};}"); + config.relaunch_policy = NoForceRelaunchAndResetState; + return config; +} + +// Tests that policies are properly loaded from NSUserDefaults when using the +// production platform policy provider. + +// Tests the value of a policy that was explicitly set. +- (void)testProductionPlatformProviderPolicyExplicitlySet { + std::unique_ptr<base::Value> searchValue = + GetPlatformPolicy("DefaultSearchProviderName"); + GREYAssertTrue(searchValue && searchValue->is_string(), + @"searchSuggestValue was not of type string"); + GREYAssertEqual(searchValue->GetString(), "Test", + @"searchSuggestValue had an unexpected value"); +} + +// Test the value of a policy that exists in the schema but was not explicitly +// set. +- (void)testProductionPlatformProviderPolicyNotSet { + std::unique_ptr<base::Value> blocklistValue = + GetPlatformPolicy("URLBlacklist"); + GREYAssertTrue(blocklistValue && blocklistValue->is_none(), + @"blocklistValue was unexpectedly present"); +} + +// Test the value of a policy that was set in the configuration but is unknown +// to the policy system. +- (void)testProductionPlatformProviderPolicyUnknown { + std::unique_ptr<base::Value> unknownValue = + GetPlatformPolicy("NotARegisteredPolicy"); + GREYAssertTrue(unknownValue && unknownValue->is_string(), + @"unknownValue was not of type string"); + GREYAssertEqual(unknownValue->GetString(), "Unknown", + @"unknownValue had an unexpected value"); +} + +@end
diff --git a/ios/chrome/browser/policy/policy_egtest_app_interface.h b/ios/chrome/browser/policy/policy_egtest_app_interface.h new file mode 100644 index 0000000..3d1febb --- /dev/null +++ b/ios/chrome/browser/policy/policy_egtest_app_interface.h
@@ -0,0 +1,19 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_POLICY_POLICY_EGTEST_APP_INTERFACE_H_ +#define IOS_CHROME_BROWSER_POLICY_POLICY_EGTEST_APP_INTERFACE_H_ + +#import <Foundation/Foundation.h> + +@interface PolicyEGTestAppInterface : NSObject + +// Returns a JSON-encoded representation of the value for the given |policyKey|. +// Looks for the policy in the platform policy provider under the CHROME policy +// namespace. ++ (NSString*)valueForPlatformPolicy:(NSString*)policyKey; + +@end + +#endif // IOS_CHROME_BROWSER_POLICY_POLICY_EGTEST_APP_INTERFACE_H_
diff --git a/ios/chrome/browser/policy/policy_egtest_app_interface.mm b/ios/chrome/browser/policy/policy_egtest_app_interface.mm new file mode 100644 index 0000000..004f384 --- /dev/null +++ b/ios/chrome/browser/policy/policy_egtest_app_interface.mm
@@ -0,0 +1,65 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/policy/policy_egtest_app_interface.h" + +#include "base/json/json_string_value_serializer.h" +#include "base/strings/sys_string_conversions.h" +#include "base/values.h" +#include "components/policy/core/browser/browser_policy_connector.h" +#include "components/policy/core/common/configuration_policy_provider.h" +#include "components/policy/core/common/policy_bundle.h" +#include "components/policy/core/common/policy_map.h" +#include "components/policy/core/common/policy_namespace.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/policy/browser_policy_connector_ios.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +// Returns a JSON-encoded string representing the given |pref|. If |pref| is +// nullptr, returns a string representing a base::Value of type NONE. +NSString* SerializedValue(const base::Value* value) { + base::Value none_value(base::Value::Type::NONE); + + if (!value) { + value = &none_value; + } + DCHECK(value); + + std::string serialized_value; + JSONStringValueSerializer serializer(&serialized_value); + serializer.Serialize(*value); + return base::SysUTF8ToNSString(serialized_value); +} + +} + +@implementation PolicyEGTestAppInterface + ++ (NSString*)valueForPlatformPolicy:(NSString*)policyKey { + const std::string key = base::SysNSStringToUTF8(policyKey); + + BrowserPolicyConnectorIOS* connector = + GetApplicationContext()->GetBrowserPolicyConnector(); + if (!connector) { + return SerializedValue(nullptr); + } + + const policy::ConfigurationPolicyProvider* platformProvider = + connector->GetPlatformProvider(); + if (!platformProvider) { + return SerializedValue(nullptr); + } + + const policy::PolicyBundle& policyBundle = platformProvider->policies(); + const policy::PolicyMap& policyMap = policyBundle.Get( + policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, "")); + return SerializedValue(policyMap.GetValue(key)); +} + +@end
diff --git a/ios/chrome/browser/policy/test_platform_policy_provider.cc b/ios/chrome/browser/policy/test_platform_policy_provider.cc new file mode 100644 index 0000000..c0c11eb5 --- /dev/null +++ b/ios/chrome/browser/policy/test_platform_policy_provider.cc
@@ -0,0 +1,13 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/policy/test_platform_policy_provider.h" + +#include "base/no_destructor.h" + +policy::MockConfigurationPolicyProvider* GetTestPlatformPolicyProvider() { + static base::NoDestructor<policy::MockConfigurationPolicyProvider> provider; + provider->SetAutoRefresh(); + return provider.get(); +}
diff --git a/ios/chrome/browser/policy/test_platform_policy_provider.h b/ios/chrome/browser/policy/test_platform_policy_provider.h new file mode 100644 index 0000000..d393eecc --- /dev/null +++ b/ios/chrome/browser/policy/test_platform_policy_provider.h
@@ -0,0 +1,15 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_POLICY_TEST_PLATFORM_POLICY_PROVIDER_H_ +#define IOS_CHROME_BROWSER_POLICY_TEST_PLATFORM_POLICY_PROVIDER_H_ + +#include "components/policy/core/common/mock_configuration_policy_provider.h" + +// Returns a singleton mock that can be installed as the platform policy +// provider when testing. Subsequent calls to this method will return the same +// object, which can then be used to update the current set of policies. +policy::MockConfigurationPolicyProvider* GetTestPlatformPolicyProvider(); + +#endif // IOS_CHROME_BROWSER_POLICY_TEST_PLATFORM_POLICY_PROVIDER_H_
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm index 2fd0d4a..9616e1c 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -2877,10 +2877,6 @@ [overlays addObject:childOverlayView]; } - // The overlay container supports at most one overlay view, either by - // presentation or by containment. - DCHECK(!presentedOverlayView || !childOverlayView); - return overlays; }
diff --git a/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm b/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm index 2444740..598c2e2 100644 --- a/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm +++ b/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm
@@ -37,6 +37,11 @@ namespace { +#if defined(CHROME_EARL_GREY_2) +// Use separate timeout for EG2 tests to accomodate for IPC delays. +const NSTimeInterval kWaitForARPresentationTimeout = 30.0; +#endif // CHROME_EARL_GREY_2 + // USDZ landing page and download request handler. std::unique_ptr<net::test_server::HttpResponse> GetResponse( const net::test_server::HttpRequest& request) { @@ -111,8 +116,9 @@ // presentation. XCUIApplication* app = [[XCUIApplication alloc] init]; XCUIElement* goodTitle = app.staticTexts[@"good"]; - GREYAssert([goodTitle waitForExistenceWithTimeout:kWaitForDownloadTimeout], - @"AR preview dialog UI was not presented"); + GREYAssert( + [goodTitle waitForExistenceWithTimeout:kWaitForARPresentationTimeout], + @"AR preview dialog UI was not presented"); #else #error Must define either CHROME_EARL_GREY_1 or CHROME_EARL_GREY_2. #endif @@ -143,7 +149,7 @@ XCUIApplication* app = [[XCUIApplication alloc] init]; XCUIElement* goodTitle = app.staticTexts[@"good"]; GREYAssertFalse( - [goodTitle waitForExistenceWithTimeout:kWaitForDownloadTimeout], + [goodTitle waitForExistenceWithTimeout:kWaitForARPresentationTimeout], @"AR preview dialog UI was presented"); #else #error Must define either CHROME_EARL_GREY_1 or CHROME_EARL_GREY_2. @@ -175,7 +181,7 @@ XCUIApplication* app = [[XCUIApplication alloc] init]; XCUIElement* goodTitle = app.staticTexts[@"good"]; GREYAssertFalse( - [goodTitle waitForExistenceWithTimeout:kWaitForDownloadTimeout], + [goodTitle waitForExistenceWithTimeout:kWaitForARPresentationTimeout], @"AR preview dialog UI was presented"); #else #error Must define either CHROME_EARL_GREY_1 or CHROME_EARL_GREY_2. @@ -207,7 +213,7 @@ XCUIApplication* app = [[XCUIApplication alloc] init]; XCUIElement* goodTitle = app.staticTexts[@"good"]; GREYAssertFalse( - [goodTitle waitForExistenceWithTimeout:kWaitForDownloadTimeout], + [goodTitle waitForExistenceWithTimeout:kWaitForARPresentationTimeout], @"AR preview dialog UI was presented"); #else #error Must define either CHROME_EARL_GREY_1 or CHROME_EARL_GREY_2.
diff --git a/ios/chrome/browser/ui/overlays/BUILD.gn b/ios/chrome/browser/ui/overlays/BUILD.gn index 7f757b0..67f7f5a 100644 --- a/ios/chrome/browser/ui/overlays/BUILD.gn +++ b/ios/chrome/browser/ui/overlays/BUILD.gn
@@ -8,13 +8,17 @@ "overlay_coordinator_factory.h", ] sources = [ + "overlay_container_coordinator+initialization.h", "overlay_container_coordinator.mm", "overlay_coordinator_factory+initialization.h", "overlay_coordinator_factory.mm", + "overlay_presentation_context_coordinator.h", + "overlay_presentation_context_coordinator.mm", "overlay_presentation_context_fullscreen_disabler.h", "overlay_presentation_context_fullscreen_disabler.mm", "overlay_presentation_context_impl.h", "overlay_presentation_context_impl.mm", + "overlay_presentation_context_impl_delegate.h", "overlay_request_ui_state.h", "overlay_request_ui_state.mm", ] @@ -28,8 +32,8 @@ ] deps = [ - ":container_ui", ":coordinators", + ":ui", "//base", "//ios/chrome/browser/main", "//ios/chrome/browser/overlays", @@ -42,15 +46,29 @@ ] } -source_set("container_ui") { +source_set("ui") { sources = [ "overlay_container_view_controller.h", "overlay_container_view_controller.mm", + "overlay_presentation_context_view_controller.h", + "overlay_presentation_context_view_controller.mm", ] configs += [ "//build/config/compiler:enable_arc" ] - deps = [ "//base" ] + deps = [ + ":presentation_controller", + "//base", + ] +} + +source_set("presentation_controller") { + sources = [ + "overlay_presentation_controller.h", + "overlay_presentation_controller.mm", + ] + + configs += [ "//build/config/compiler:enable_arc" ] } source_set("coordinators") { @@ -75,6 +93,8 @@ source_set("util") { sources = [ + "overlay_presentation_context_util.h", + "overlay_presentation_context_util.mm", "overlay_request_mediator_util.h", "overlay_request_mediator_util.mm", ] @@ -91,7 +111,12 @@ source_set("unit_tests") { testonly = true sources = [ + "overlay_container_coordinator_unittest.mm", + "overlay_container_view_controller_unittest.mm", + "overlay_presentation_context_coordinator_unittest.mm", "overlay_presentation_context_fullscreen_disabler_unittest.mm", + "overlay_presentation_context_impl_unittest.mm", + "overlay_presentation_context_view_controller_unittest.mm", "overlay_request_mediator_unittest.mm", "overlay_request_mediator_util_unittest.mm", "overlay_request_ui_state_unittest.mm", @@ -102,14 +127,17 @@ deps = [ ":coordinators", ":overlays", + ":ui", ":util", "//base/test:test_support", "//ios/chrome/browser/main:test_support", "//ios/chrome/browser/overlays", + "//ios/chrome/browser/overlays/public/test_modality", "//ios/chrome/browser/overlays/public/web_content_area", "//ios/chrome/browser/overlays/test", "//ios/chrome/browser/ui/fullscreen", "//ios/chrome/browser/ui/overlays/test", + "//ios/chrome/browser/ui/overlays/test_modality", "//ios/chrome/browser/web_state_list", "//ios/chrome/test:test_support", "//ios/web/public/test",
diff --git a/ios/chrome/browser/ui/overlays/overlay_container_coordinator+initialization.h b/ios/chrome/browser/ui/overlays/overlay_container_coordinator+initialization.h new file mode 100644 index 0000000..748bcf7 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_container_coordinator+initialization.h
@@ -0,0 +1,27 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_CONTAINER_COORDINATOR_INITIALIZATION_H_ +#define IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_CONTAINER_COORDINATOR_INITIALIZATION_H_ + +#import "ios/chrome/browser/ui/overlays/overlay_container_coordinator.h" + +class OverlayPresentationContextImpl; + +// TODO(crbug.com/1056837): This initializer is only necessary to prevent the +// test modality code from getting compiled into releases, and can be removed +// once OverlayModality is converted from an enum to a class. +@interface OverlayContainerCoordinator (Initialization) + +// Initializer for a coordinator that manages the base UIViewController for +// overlay UI implemented using child UIViewControllers for |context| at +// |modality|. +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browser:(Browser*)browser + presentationContext: + (OverlayPresentationContextImpl*)context; + +@end + +#endif // IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_CONTAINER_COORDINATOR_INITIALIZATION_H_
diff --git a/ios/chrome/browser/ui/overlays/overlay_container_coordinator.h b/ios/chrome/browser/ui/overlays/overlay_container_coordinator.h index 5533d57..89a5e5d 100644 --- a/ios/chrome/browser/ui/overlays/overlay_container_coordinator.h +++ b/ios/chrome/browser/ui/overlays/overlay_container_coordinator.h
@@ -10,17 +10,20 @@ #include "ios/chrome/browser/overlays/public/overlay_modality.h" #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" -// Coordinator that manages displaying of UI for OverlayRequests. An instance -// of this coordinator should be created for each Browser at every -// OverlayModality. +// Coordinator that manages the container view in which overlay UI is displayed. +// The coordinator's view controller should be used to display overlay UI +// implemented using child UIViewControllers. @interface OverlayContainerCoordinator : ChromeCoordinator // Initializer for an overlay container that presents overlay for |browser| at // |modality|. +// TODO(crbug.com/1056837): This is not marked as NS_DESIGNATED_INITIALIZER to +// facilitate the creation of OverlayContainerCoordinators for +// OverlayModality::kTesting. Annotate as NS_DESIGNATED_INITIALIZER once +// OverlayModality is converted from an enum type. - (instancetype)initWithBaseViewController:(UIViewController*)viewController browser:(Browser*)browser - modality:(OverlayModality)modality - NS_DESIGNATED_INITIALIZER; + modality:(OverlayModality)modality; - (instancetype)initWithBaseViewController:(UIViewController*)viewController browserState:(ChromeBrowserState*)browserState NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/overlays/overlay_container_coordinator.mm b/ios/chrome/browser/ui/overlays/overlay_container_coordinator.mm index 59d774e..9cae1e9 100644 --- a/ios/chrome/browser/ui/overlays/overlay_container_coordinator.mm +++ b/ios/chrome/browser/ui/overlays/overlay_container_coordinator.mm
@@ -3,15 +3,17 @@ // found in the LICENSE file. #import "ios/chrome/browser/ui/overlays/overlay_container_coordinator.h" +#import "ios/chrome/browser/ui/overlays/overlay_container_coordinator+initialization.h" -#include <map> #include <memory> #include "base/logging.h" #include "base/scoped_observer.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/ui/overlays/overlay_container_view_controller.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator.h" #import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl_delegate.h" #import "ios/chrome/common/ui/util/constraints_ui_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -19,15 +21,18 @@ #endif @interface OverlayContainerCoordinator () < - OverlayContainerViewControllerDelegate> + OverlayContainerViewControllerDelegate, + OverlayPresentationContextImplDelegate> // Whether the coordinator is started. @property(nonatomic, assign, getter=isStarted) BOOL started; // The presentation context used by OverlayPresenter to drive presentation for // this container. -@property(nonatomic, readonly) +@property(nonatomic, assign, readonly) OverlayPresentationContextImpl* presentationContext; -// The modality being handled by the container. -@property(nonatomic, assign) OverlayModality modality; +// The coordinator that manages the base view for overlay UI displayed using +// UIViewController presentation. +@property(nonatomic, strong) + OverlayPresentationContextCoordinator* presentationContextCoordinator; @end @implementation OverlayContainerCoordinator @@ -35,17 +40,11 @@ - (instancetype)initWithBaseViewController:(UIViewController*)viewController browser:(Browser*)browser modality:(OverlayModality)modality { - if (self = [super initWithBaseViewController:viewController - browser:browser]) { - OverlayPresentationContextImpl::Container::CreateForUserData(browser, - browser); - _presentationContext = - OverlayPresentationContextImpl::Container::FromUserData(browser) - ->PresentationContextForModality(modality); - DCHECK(_presentationContext); - _modality = modality; - } - return self; + OverlayPresentationContextImpl* context = + OverlayPresentationContextImpl::FromBrowser(browser, modality); + return [self initWithBaseViewController:viewController + browser:browser + presentationContext:context]; } #pragma mark - ChromeCoordinator @@ -54,27 +53,39 @@ if (self.started) return; self.started = YES; - // Create the container view controller and add it to the base view - // controller. + // Create the container view controller. OverlayContainerViewController* viewController = [[OverlayContainerViewController alloc] init]; viewController.definesPresentationContext = YES; viewController.delegate = self; _viewController = viewController; + // Set the coordinator as the delegate for the presentation context. + self.presentationContext->SetDelegate(self); + // Create the presentation context coordinator. It is started when the + // container view controller is finished being added to the window, as its + // presentation would no-op if started too early. + self.presentationContextCoordinator = + [[OverlayPresentationContextCoordinator alloc] + initWithBaseViewController:_viewController + browser:self.browser + presentationContext:self.presentationContext]; + // Add the container view controller to the hierarchy. UIView* containerView = _viewController.view; containerView.translatesAutoresizingMaskIntoConstraints = NO; [self.baseViewController addChildViewController:_viewController]; [self.baseViewController.view addSubview:containerView]; AddSameConstraints(containerView, self.baseViewController.view); [_viewController didMoveToParentViewController:self.baseViewController]; - self.presentationContext->SetCoordinator(self); } - (void)stop { if (!self.started) return; self.started = NO; - self.presentationContext->SetCoordinator(nil); + self.presentationContext->SetDelegate(nil); + // Clean up the presentation context coordinator. + [self.presentationContextCoordinator stop]; + self.presentationContextCoordinator = nil; // Remove the container view and reset the view controller. [_viewController willMoveToParentViewController:nil]; [_viewController.view removeFromSuperview]; @@ -87,7 +98,53 @@ - (void)containerViewController: (OverlayContainerViewController*)containerViewController didMoveToWindow:(UIWindow*)window { - self.presentationContext->WindowDidChange(); + self.presentationContext->SetWindow(window); +} + +#pragma mark - OverlayPresentationContextImplDelegate + +- (void)updatePresentationContext:(OverlayPresentationContextImpl*)context + forPresentationCapabilities: + (OverlayPresentationContext::UIPresentationCapabilities)capabilities { + DCHECK_EQ(self.presentationContext, context); + DCHECK(self.started); + DCHECK(self.viewController); + + // Update the context's container view controller. + bool needsContainer = + capabilities & + OverlayPresentationContext::UIPresentationCapabilities::kContained; + self.presentationContext->SetContainerViewController( + needsContainer ? self.viewController : nil); + + // Start or stop the presentation context coordinator depending on whether + // it is required to support |capabilities|. + if (capabilities & + OverlayPresentationContext::UIPresentationCapabilities::kPresented) { + // The coordinator cannot be started if its base UIViewController doesn't + // belong to a window. The context will re-request the kPresented + // capability when the view moves to a window. + if (self.viewController.view.window) + [self.presentationContextCoordinator start]; + } else { + [self.presentationContextCoordinator stop]; + } +} + +@end + +@implementation OverlayContainerCoordinator (Initialization) + +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browser:(Browser*)browser + presentationContext: + (OverlayPresentationContextImpl*)context { + if (self = [super initWithBaseViewController:viewController + browser:browser]) { + DCHECK(context); + _presentationContext = context; + } + return self; } @end
diff --git a/ios/chrome/browser/ui/overlays/overlay_container_coordinator_unittest.mm b/ios/chrome/browser/ui/overlays/overlay_container_coordinator_unittest.mm new file mode 100644 index 0000000..99ce990 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_container_coordinator_unittest.mm
@@ -0,0 +1,111 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/overlay_container_coordinator.h" +#import "ios/chrome/browser/ui/overlays/overlay_container_coordinator+initialization.h" + +#import "base/test/ios/wait_util.h" +#import "ios/chrome/browser/main/test_browser.h" +#include "ios/chrome/browser/overlays/public/overlay_request.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_contained_overlay_request_config.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_presented_overlay_request_config.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_util.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller.h" +#include "ios/chrome/browser/ui/overlays/test/fake_overlay_request_coordinator_delegate.h" +#import "ios/chrome/browser/ui/overlays/test/test_overlay_presentation_context.h" +#include "ios/chrome/test/scoped_key_window.h" +#include "ios/web/public/test/web_task_environment.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using base::test::ios::WaitUntilConditionOrTimeout; +using base::test::ios::kWaitForUIElementTimeout; + +// Test fixture for OverlayContainerCoordinator. +class OverlayContainerCoordinatorTest : public PlatformTest { + public: + OverlayContainerCoordinatorTest() + : browser_(std::make_unique<TestBrowser>()), + context_(browser_.get()), + root_view_controller_([[UIViewController alloc] init]), + coordinator_([[OverlayContainerCoordinator alloc] + initWithBaseViewController:root_view_controller_ + browser:browser_.get() + presentationContext:&context_]) { + root_view_controller_.definesPresentationContext = YES; + scoped_window_.Get().rootViewController = root_view_controller_; + } + ~OverlayContainerCoordinatorTest() override { + // The browser needs to be destroyed before |context_| so that observers + // can be unhooked due to BrowserDestroyed(). This is not a problem for + // non-test OverlayPresentationContextImpls since they're owned by the + // Browser and get destroyed after BrowserDestroyed() is called. + browser_ = nullptr; + } + + protected: + web::WebTaskEnvironment task_environment_; + std::unique_ptr<TestBrowser> browser_; + TestOverlayPresentationContext context_; + ScopedKeyWindow scoped_window_; + UIViewController* root_view_controller_ = nil; + OverlayContainerCoordinator* coordinator_ = nil; +}; + +// Tests that the coordinator updates its OverlayPresentationContext's +// presentation capabilities when started and stopped. +TEST_F(OverlayContainerCoordinatorTest, UpdatePresentationCapabilities) { + ASSERT_FALSE(OverlayPresentationContextSupportsContainedUI(&context_)); + + // Start the coordinator and verify that the presentation context begins + // supporting contained overlay UI. + [coordinator_ start]; + std::unique_ptr<OverlayRequest> request = + OverlayRequest::CreateWithConfig<TestContainedOverlay>(); + context_.PrepareToShowOverlayUI(request.get()); + EXPECT_TRUE(OverlayPresentationContextSupportsContainedUI(&context_)); + + // Stop the coordinator and verify that the presentation context no longer + // supports contained overlay UI. + [coordinator_ stop]; + EXPECT_FALSE(OverlayPresentationContextSupportsContainedUI(&context_)); +} + +// Tests that the coordinator sets up the presentation context upon being added +// to the window. +TEST_F(OverlayContainerCoordinatorTest, PresentationContextSetup) { + ASSERT_FALSE(OverlayPresentationContextSupportsPresentedUI(&context_)); + + // Start the coordinator. This will add it to the key window, triggering the + // presentation of the UIViewController that will be used as the base for + // overlay UI implemented using presentation. + [coordinator_ start]; + std::unique_ptr<OverlayRequest> request = + OverlayRequest::CreateWithConfig<TestPresentedOverlay>(); + context_.PrepareToShowOverlayUI(request.get()); + UIViewController* presented_view_controller = + coordinator_.viewController.presentedViewController; + ASSERT_TRUE(presented_view_controller); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return presented_view_controller.presentingViewController && + !presented_view_controller.beingPresented; + })); + + // Once |presented_view_controller| is finished being presented, it should + // update the presentation capabilities to allow presented overlay UI. + EXPECT_TRUE(OverlayPresentationContextSupportsPresentedUI(&context_)); + + // Stop the container coordinator and wait for |presented_view_controller| to + // finish being dismissed, verifying that the context no longer supports + // presented overlay UI. + [coordinator_ stop]; + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return !presented_view_controller.presentingViewController; + })); + EXPECT_FALSE(OverlayPresentationContextSupportsPresentedUI(&context_)); +}
diff --git a/ios/chrome/browser/ui/overlays/overlay_container_view_controller.mm b/ios/chrome/browser/ui/overlays/overlay_container_view_controller.mm index 75ab844..62aa3bb 100644 --- a/ios/chrome/browser/ui/overlays/overlay_container_view_controller.mm +++ b/ios/chrome/browser/ui/overlays/overlay_container_view_controller.mm
@@ -22,6 +22,17 @@ return hitView == self ? nil : hitView; } +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event { + // Only register touches that land inside a subview. Otherwise, return NO to + // allow touches to continue to the underlying UI. + for (UIView* subview in self.subviews) { + CGPoint adjustedPoint = [subview convertPoint:point fromView:self]; + if ([subview pointInside:adjustedPoint withEvent:event]) + return YES; + } + return NO; +} + - (void)didMoveToWindow { [super didMoveToWindow]; [self.viewController.delegate containerViewController:self.viewController
diff --git a/ios/chrome/browser/ui/overlays/overlay_container_view_controller_unittest.mm b/ios/chrome/browser/ui/overlays/overlay_container_view_controller_unittest.mm new file mode 100644 index 0000000..6b78cf1 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_container_view_controller_unittest.mm
@@ -0,0 +1,93 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/overlay_container_view_controller.h" + +#import "ios/chrome/browser/main/test_browser.h" +#include "ios/chrome/browser/overlays/public/overlay_request.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_presented_overlay_request_config.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h" +#include "ios/chrome/browser/ui/overlays/test/fake_overlay_request_coordinator_delegate.h" +#import "ios/chrome/browser/ui/overlays/test_modality/test_presented_overlay_coordinator.h" +#import "ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator.h" +#include "ios/chrome/test/scoped_key_window.h" +#include "ios/web/public/test/web_task_environment.h" +#include "testing/platform_test.h" +#import "third_party/ocmock/OCMock/OCMock.h" +#import "third_party/ocmock/gtest_support.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +// Test fixture for OverlayContainerViewController. +class OverlayContainerViewControllerTest : public PlatformTest { + public: + OverlayContainerViewControllerTest() + : root_view_controller_([[UIViewController alloc] init]), + delegate_(OCMStrictProtocolMock( + @protocol(OverlayContainerViewControllerDelegate))), + view_controller_([[OverlayContainerViewController alloc] init]) { + scoped_window_.Get().rootViewController = root_view_controller_; + view_controller_.delegate = delegate_; + } + ~OverlayContainerViewControllerTest() override { + EXPECT_OCMOCK_VERIFY(delegate_); + } + + protected: + ScopedKeyWindow scoped_window_; + UIViewController* root_view_controller_ = nil; + id<OverlayContainerViewControllerDelegate> delegate_ = nil; + OverlayContainerViewController* view_controller_ = nil; +}; + +// Verifies that the view controller notifies its delegate when its view's +// window is changed. +TEST_F(OverlayContainerViewControllerTest, MoveToWindow) { + OCMExpect([delegate_ containerViewController:view_controller_ + didMoveToWindow:scoped_window_.Get()]); + [root_view_controller_.view addSubview:view_controller_.view]; + + OCMExpect([delegate_ containerViewController:view_controller_ + didMoveToWindow:nil]); + [view_controller_.view removeFromSuperview]; +} + +// Verifies that the container view ignores touches that fall outside of any +// subviews. +TEST_F(OverlayContainerViewControllerTest, TouchHandling) { + // The container view will be laid out with |frame|. A subview will be added + // to the view and laid out |subview_inset| from the edges of the view. + CGRect frame = CGRectMake(0.0, 0.0, 100.0, 100.0); + CGFloat subview_inset = 25.0; + CGRect subview_frame = CGRectInset(frame, subview_inset, subview_inset); + + // |center| is the center of the container view, which will land in the center + // of the added subview. |corner| is a point halfway between the container + // view's origin and the subview's origin. + CGPoint center = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame)); + CGPoint corner = CGPointMake(subview_inset / 2.0, subview_inset / 2.0); + + // Set up the view hierarchy using the calculated frames. + UIView* view = view_controller_.view; + view.frame = frame; + UIView* subview = [[UIView alloc] initWithFrame:subview_frame]; + [view addSubview:subview]; + + // Verify that touches are ignored when they fall outside of any subview. + EXPECT_FALSE([view hitTest:corner withEvent:nil]); + EXPECT_FALSE([view pointInside:corner withEvent:nil]); + + // Verify that touches are handled and forwarded to |subview| when falling + // inside |subview|'s bounds. + EXPECT_EQ([view hitTest:center withEvent:nil], subview); + EXPECT_TRUE([view pointInside:center withEvent:nil]); + + // Remove the subview and verify that touches in the center are ignored. + [subview removeFromSuperview]; + EXPECT_FALSE([view hitTest:center withEvent:nil]); + EXPECT_FALSE([view pointInside:center withEvent:nil]); +}
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator.h b/ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator.h new file mode 100644 index 0000000..d73f740f0 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator.h
@@ -0,0 +1,46 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_COORDINATOR_H_ +#define IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_COORDINATOR_H_ + +#import <UIKit/UIKit.h> + +#include "ios/chrome/browser/overlays/public/overlay_modality.h" +#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" + +class OverlayPresentationContextImpl; + +// Coordinator whose presentation context is used for overlay presentation. +// Manages a UIViewController that is presented over the overlay container's +// UIViewController presentation context. This is necessary due to UIKit's +// custom UIViewController presentation implementation. The only way to +// present non-modally with UIModalPresentationStyleCustom is by using a custom +// UIPresentationController whose |shouldPresentInFullscreen| property is NO. +// When such a presentation controller is provided, UIKit traverses the view +// hierarchy to find the nearest presented UIViewController. By presenting a +// UIViewController over a child UIViewController whose +// |definesPresentationContext| property is YES, this coordinator inserts a +// UIKit presentation context upon which custom presentation can occur. +@interface OverlayPresentationContextCoordinator : ChromeCoordinator + +// Initializer for an overlay container that presents overlay for |browser| at +// |modality|. +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browser:(Browser*)browser + presentationContext: + (OverlayPresentationContextImpl*)context + NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browserState:(ChromeBrowserState*)browserState + NS_UNAVAILABLE; +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browser:(Browser*)browser NS_UNAVAILABLE; + +// The view controller whose presentation context is used to present overlays. +@property(nonatomic, readonly) UIViewController* viewController; + +@end + +#endif // IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator.mm new file mode 100644 index 0000000..3442db5c9 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator.mm
@@ -0,0 +1,83 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator.h" + +#include <memory> + +#import "base/ios/block_types.h" +#include "base/logging.h" +#include "base/scoped_observer.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface OverlayPresentationContextCoordinator () +// Whether the coordinator is started. +@property(nonatomic, assign, getter=isStarted) BOOL started; +// The presentation context used by OverlayPresenter to drive presentation for +// this container. +@property(nonatomic, assign, readonly) + OverlayPresentationContextImpl* presentationContext; +@end + +@implementation OverlayPresentationContextCoordinator + +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browser:(Browser*)browser + presentationContext: + (OverlayPresentationContextImpl*)context { + if (self = [super initWithBaseViewController:viewController + browser:browser]) { + DCHECK(context); + _presentationContext = context; + } + return self; +} + +#pragma mark - ChromeCoordinator + +- (void)start { + if (self.started) + return; + self.started = YES; + // Create the presentation context view controller and present it over the + // base view's presentation context. + _viewController = [[OverlayPresentationContextViewController alloc] init]; + _viewController.definesPresentationContext = YES; + _viewController.modalPresentationStyle = + UIModalPresentationOverCurrentContext; + DCHECK(self.baseViewController.definesPresentationContext); + // Supply the view controller to the presentation context upon completion of + // the presentation. If the coordinator is deallocated before the completion + // block is called, then the presentation context's view controller will + // remain null, which is correct behavior since the coordinator is unable to + // support overlay UI presentation. + __weak __typeof(self) weakSelf = self; + ProceduralBlock completion = ^{ + if (!weakSelf) + return; + __typeof(self) strongSelf = weakSelf; + strongSelf.presentationContext->SetPresentationContextViewController( + strongSelf.viewController); + }; + [self.baseViewController presentViewController:_viewController + animated:NO + completion:completion]; +} + +- (void)stop { + if (!self.started) + return; + self.started = NO; + self.presentationContext->SetPresentationContextViewController(nil); + // Dismiss the presentation context view controller. + [self.baseViewController dismissViewControllerAnimated:NO completion:nil]; + _viewController = nil; +} + +@end
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator_unittest.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator_unittest.mm new file mode 100644 index 0000000..07f8599 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator_unittest.mm
@@ -0,0 +1,87 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator.h" + +#import "base/test/ios/wait_util.h" +#import "ios/chrome/browser/main/test_browser.h" +#include "ios/chrome/browser/overlays/public/overlay_request.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_presented_overlay_request_config.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_util.h" +#include "ios/chrome/browser/ui/overlays/test/fake_overlay_request_coordinator_delegate.h" +#import "ios/chrome/browser/ui/overlays/test/test_overlay_presentation_context.h" +#include "ios/chrome/test/scoped_key_window.h" +#include "ios/web/public/test/web_task_environment.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using base::test::ios::WaitUntilConditionOrTimeout; +using base::test::ios::kWaitForUIElementTimeout; + +// Test fixture for OverlayPresentationContextCoordinator. +class OverlayPresentationContextCoordinatorTest : public PlatformTest { + public: + OverlayPresentationContextCoordinatorTest() + : browser_(std::make_unique<TestBrowser>()), + context_(browser_.get()), + root_view_controller_([[UIViewController alloc] init]), + coordinator_([[OverlayPresentationContextCoordinator alloc] + initWithBaseViewController:root_view_controller_ + browser:browser_.get() + presentationContext:&context_]) { + root_view_controller_.definesPresentationContext = YES; + scoped_window_.Get().rootViewController = root_view_controller_; + } + ~OverlayPresentationContextCoordinatorTest() override { + // The browser needs to be destroyed before |context_| so that observers + // can be unhooked due to BrowserDestroyed(). This is not a problem for + // non-test OverlayPresentationContextImpls since they're owned by the + // Browser and get destroyed after BrowserDestroyed() is called. + browser_ = nullptr; + } + + protected: + web::WebTaskEnvironment task_environment_; + std::unique_ptr<TestBrowser> browser_; + TestOverlayPresentationContext context_; + ScopedKeyWindow scoped_window_; + UIViewController* root_view_controller_ = nil; + OverlayPresentationContextCoordinator* coordinator_ = nil; +}; + +// Tests that the coordinator updates its OverlayPresentationContext's +// presentation capabilities when started and stopped. +TEST_F(OverlayPresentationContextCoordinatorTest, + UpdatePresentationCapabilities) { + ASSERT_FALSE(OverlayPresentationContextSupportsPresentedUI(&context_)); + + // Start the coordinator and wait until the view is finished being presented. + // This is necessary because UIViewController presentation is asynchronous, + // even when performed without animation. + [coordinator_ start]; + UIViewController* view_controller = coordinator_.viewController; + ASSERT_TRUE(view_controller); + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return view_controller.presentingViewController && + !view_controller.beingPresented; + })); + + // Verify that the presentation context supports presentation. + EXPECT_TRUE(OverlayPresentationContextSupportsPresentedUI(&context_)); + + // Stop the coordinator and wait until the view is finished being dismissed. + // This is necessary because UIViewController presentation is asynchronous, + // even when performed without animation. + [coordinator_ stop]; + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return !view_controller.presentingViewController; + })); + + // Verify that the presentation context no longer supports presentation. + EXPECT_FALSE(OverlayPresentationContextSupportsPresentedUI(&context_)); +}
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h index a6d6902..6b0475df 100644 --- a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h
@@ -5,6 +5,8 @@ #ifndef IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_IMPL_H_ #define IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_IMPL_H_ +#import <UIKit/UIKit.h> + #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #import "ios/chrome/browser/main/browser_observer.h" @@ -17,17 +19,23 @@ #import "ios/chrome/browser/ui/overlays/overlay_request_ui_state.h" @class OverlayRequestCoordinatorFactory; -@class OverlayContainerCoordinator; +@class OverlayPresentationContextCoordinator; +@protocol OverlayPresentationContextImplDelegate; // Implementation of OverlayPresentationContext. An instance of this class // exists for every OverlayModality for each Browser. This delegate is scoped // to the Browser because it needs to store state even when a Browser's UI is -// not on screen. When a Browser's UI is shown, the OverlayContainerCoordinator -// for each of its OverlayModalities will supply itself to the delegate, which -// will then present the UI using the container coordinator's presentation -// context. +// not on screen. When a Browser's UI is shown, the view controllers for each +// modality are set up. When the presentation context is supplied with a +// container or presentation context UIViewController, its presentation +// capabilities are updated and supported overlay UI can begin being shown in +// the context. class OverlayPresentationContextImpl : public OverlayPresentationContext { public: + // Returns the OverlayPresentationContextImpl for |browser| at |modality|. + static OverlayPresentationContextImpl* FromBrowser(Browser* browser, + OverlayModality modality); + ~OverlayPresentationContextImpl() override; // Container that stores the UI delegate for each modality. Usage example: @@ -51,14 +59,21 @@ ui_delegates_; }; - // The OverlayContainerCoordinator is used to present the overlay UI at the - // correct modality in the app. Should only be set when the coordinator is - // started. - OverlayContainerCoordinator* coordinator() const { return coordinator_; } - void SetCoordinator(OverlayContainerCoordinator* coordinator); + // The context's delegate. + void SetDelegate(id<OverlayPresentationContextImplDelegate> delegate); - // Called when |coordinator_|'s view was moved to a new window. - void WindowDidChange(); + // The window in which overlay UI will be presented. + void SetWindow(UIWindow* window); + + // The UIViewController used for overlays displayed using child + // UIViewControllers. Setting to a new value updates the presentation + // capabilities to include kContained. + void SetContainerViewController(UIViewController* view_controller); + + // The UIViewController used for overlays displayed using presented + // UIViewControllers. Setting to a new value updates the presentation + // capabilities to include kPresented. + void SetPresentationContextViewController(UIViewController* view_controller); // OverlayPresentationContext: void AddObserver(OverlayPresentationContextObserver* observer) override; @@ -69,6 +84,7 @@ UIPresentationCapabilities capabilities) const override; bool CanShowUIForRequest(OverlayRequest* request) const override; bool IsShowingOverlayUI() const override; + void PrepareToShowOverlayUI(OverlayRequest* request) override; void ShowOverlayUI(OverlayRequest* request, OverlayPresentationCallback presentation_callback, OverlayDismissalCallback dismissal_callback) override; @@ -88,12 +104,27 @@ // present the UI for |request|. void SetRequest(OverlayRequest* request); + // Returns whether |request| uses a child UIViewController. If false, the + // request's UI is shown using presentation. + bool RequestUsesChildViewController(OverlayRequest* request) const; + + // Returns the base view controller to use for |request|'s coordinator, or + // nullptr if the base has not been provided. |container_view_controller_| is + // returned if |request| uses a child UIViewController, and + // |presentation_context_view_controller_| is returned if |request| uses + // UIViewController presentation. + UIViewController* GetBaseViewController(OverlayRequest* request) const; + // Returns the UI state for |request|. OverlayRequestUIState* GetRequestUIState(OverlayRequest* request); - // Updates |coordinator_| and |presentation_capabilities_| using - // |coordinator|. - void UpdateForCoordinator(OverlayContainerCoordinator* coordinator); + // Returns the presentation capabilities required to show |request|. + UIPresentationCapabilities GetRequiredPresentationCapabilities( + OverlayRequest* request) const; + + // Updates the presentation capabilities based on the provided + // UIViewControllers. + void UpdatePresentationCapabilities(); // Shows the UI for the presented request using the container coordinator. void ShowUIForPresentedRequest(); @@ -149,15 +180,22 @@ // The coordinator factory that provides the UI for the overlays at this // modality. OverlayRequestCoordinatorFactory* coordinator_factory_ = nil; - // The coordinator responsible for presenting the UI delegate's UI. - OverlayContainerCoordinator* coordinator_ = nil; + // The context's delegate. + __weak id<OverlayPresentationContextImplDelegate> delegate_ = nil; + // The window in which overlay UI will be presented. + UIWindow* window_ = nil; + // The UIViewController used as the base for overlays UI displayed using child + // UIViewControllers. + UIViewController* container_view_controller_ = nil; + // The UIViewController used as the base for overlays displayed using + // presented UIViewControllers. + UIViewController* presentation_context_view_controller_ = nil; // The presentation capabilities of |coordinator_|'s view controller. UIPresentationCapabilities presentation_capabilities_ = UIPresentationCapabilities::kNone; - // The request that is currently presented by |presenter_|. The UI for this - // request might not yet be visible if no OverlayContainerCoordinator has been - // provided. When a new request is presented, the UI state for the request - // will be added to |states_|. + // The request that is currently presented by |presenter_|. When a new + // request is presented, the UI state for the request will be added to + // |states_|. OverlayRequest* request_ = nullptr; // Map storing the UI state for each OverlayRequest. std::map<OverlayRequest*, std::unique_ptr<OverlayRequestUIState>> states_;
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm index 7af1b67..6ee79f90b 100644 --- a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.mm
@@ -12,13 +12,24 @@ #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h" #import "ios/chrome/browser/overlays/public/overlay_presenter.h" -#import "ios/chrome/browser/ui/overlays/overlay_container_coordinator.h" #import "ios/chrome/browser/ui/overlays/overlay_coordinator_factory.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_coordinator.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl_delegate.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif +// static +OverlayPresentationContextImpl* OverlayPresentationContextImpl::FromBrowser( + Browser* browser, + OverlayModality modality) { + OverlayPresentationContextImpl::Container::CreateForUserData(browser, + browser); + return OverlayPresentationContextImpl::Container::FromUserData(browser) + ->PresentationContextForModality(modality); +} + #pragma mark - OverlayPresentationContextImpl::Container OVERLAY_USER_DATA_SETUP_IMPL(OverlayPresentationContextImpl::Container); @@ -71,19 +82,49 @@ #pragma mark Public -void OverlayPresentationContextImpl::SetCoordinator( - OverlayContainerCoordinator* coordinator) { - if (coordinator_ == coordinator) +void OverlayPresentationContextImpl::SetDelegate( + id<OverlayPresentationContextImplDelegate> delegate) { + if (delegate_ == delegate) return; + // Reset the presentation capabilities. + container_view_controller_ = nil; + presentation_context_view_controller_ = nil; + UpdatePresentationCapabilities(); - UpdateForCoordinator(coordinator); + delegate_ = delegate; - // The new coordinator should be started before provided to the UI delegate. - DCHECK(!coordinator_ || coordinator_.viewController); + // The context is only capable of presenting once the delegate is provided. + presenter_->SetPresentationContext(delegate_ ? this : nullptr); } -void OverlayPresentationContextImpl::WindowDidChange() { - UpdateForCoordinator(coordinator_); +void OverlayPresentationContextImpl::SetWindow(UIWindow* window) { + if (window_ == window) + return; + window_ = window; + for (auto& observer : observers_) { + observer.OverlayPresentationContextDidMoveToWindow(this, window_); + } +} + +void OverlayPresentationContextImpl::SetContainerViewController( + UIViewController* view_controller) { + if (container_view_controller_ == view_controller) + return; + container_view_controller_ = view_controller; + UpdatePresentationCapabilities(); +} + +void OverlayPresentationContextImpl::SetPresentationContextViewController( + UIViewController* view_controller) { + if (presentation_context_view_controller_ == view_controller) + return; + presentation_context_view_controller_ = view_controller; + // |view_controller| should not be provided to the context until it is fully + // presented in a window. + DCHECK(!view_controller || + (view_controller.presentationController.containerView.window && + !view_controller.beingPresented && !view_controller.beingDismissed)); + UpdatePresentationCapabilities(); } #pragma mark OverlayPresentationContext @@ -106,11 +147,8 @@ bool OverlayPresentationContextImpl::CanShowUIForRequest( OverlayRequest* request, UIPresentationCapabilities capabilities) const { - BOOL uses_child_view_controller = [coordinator_factory_ - coordinatorForRequestUsesChildViewController:request]; UIPresentationCapabilities required_capability = - uses_child_view_controller ? UIPresentationCapabilities::kContained - : UIPresentationCapabilities::kPresented; + GetRequiredPresentationCapabilities(request); return !!(capabilities & required_capability); } @@ -123,6 +161,19 @@ return !!request_; } +void OverlayPresentationContextImpl::PrepareToShowOverlayUI( + OverlayRequest* request) { + // Early return if the request is already supported. + if (CanShowUIForRequest(request)) + return; + + // Request the delegate to prepare for overlay UI with |required_capability|. + UIPresentationCapabilities required_capabilities = + GetRequiredPresentationCapabilities(request); + [delegate_ updatePresentationContext:this + forPresentationCapabilities:required_capabilities]; +} + void OverlayPresentationContextImpl::ShowOverlayUI( OverlayRequest* request, OverlayPresentationCallback presentation_callback, @@ -139,9 +190,7 @@ } void OverlayPresentationContextImpl::HideOverlayUI(OverlayRequest* request) { - DCHECK(CanShowUIForRequest(request)); DCHECK_EQ(request_, request); - DCHECK(CanShowUIForRequest(request)); OverlayRequestUIState* state = GetRequestUIState(request_); DCHECK(state->has_callback()); @@ -153,7 +202,6 @@ void OverlayPresentationContextImpl::CancelOverlayUI( OverlayRequest* request) { - DCHECK(CanShowUIForRequest(request)); // No cleanup required if there is no UI state for |request|. This can // occur when cancelling an OverlayRequest whose UI has never been // presented. @@ -200,25 +248,48 @@ // The UI state should be created before resetting the presented request. DCHECK(GetRequestUIState(request_)); ShowUIForPresentedRequest(); + } else { + // Inform the delegate that no presentation capabilities are currently + // required. + [delegate_ updatePresentationContext:this + forPresentationCapabilities:UIPresentationCapabilities::kNone]; } } +bool OverlayPresentationContextImpl::RequestUsesChildViewController( + OverlayRequest* request) const { + return [coordinator_factory_ + coordinatorForRequestUsesChildViewController:request]; +} + +UIViewController* OverlayPresentationContextImpl::GetBaseViewController( + OverlayRequest* request) const { + return RequestUsesChildViewController(request) + ? container_view_controller_ + : presentation_context_view_controller_; +} + OverlayRequestUIState* OverlayPresentationContextImpl::GetRequestUIState( OverlayRequest* request) { return request ? states_[request].get() : nullptr; } -void OverlayPresentationContextImpl::UpdateForCoordinator( - OverlayContainerCoordinator* coordinator) { +OverlayPresentationContext::UIPresentationCapabilities +OverlayPresentationContextImpl::GetRequiredPresentationCapabilities( + OverlayRequest* request) const { + BOOL uses_child_view_controller = [coordinator_factory_ + coordinatorForRequestUsesChildViewController:request]; + return uses_child_view_controller ? UIPresentationCapabilities::kContained + : UIPresentationCapabilities::kPresented; +} + +void OverlayPresentationContextImpl::UpdatePresentationCapabilities() { UIPresentationCapabilities capabilities = UIPresentationCapabilities::kNone; - UIViewController* view_controller = coordinator.viewController; - // Any UIViewController can contain overlay UI as a child. - if (view_controller) { + if (container_view_controller_) { capabilities = static_cast<UIPresentationCapabilities>( capabilities | UIPresentationCapabilities::kContained); } - // Only UIViewControllers attached to a window can present overlay UI. - if (view_controller.view.window) { + if (presentation_context_view_controller_) { capabilities = static_cast<UIPresentationCapabilities>( capabilities | UIPresentationCapabilities::kPresented); } @@ -232,7 +303,6 @@ } presentation_capabilities_ = capabilities; - coordinator_ = coordinator; if (capabilities_changed) { for (auto& observer : observers_) { @@ -250,14 +320,14 @@ // Create the coordinator if necessary. OverlayRequestUIState* state = GetRequestUIState(request_); - UIViewController* container_view_controller = coordinator_.viewController; OverlayRequestCoordinator* overlay_coordinator = state->coordinator(); + UIViewController* base_view_controller = GetBaseViewController(request_); if (!overlay_coordinator || - overlay_coordinator.baseViewController != container_view_controller) { - overlay_coordinator = [coordinator_factory_ - newCoordinatorForRequest:request_ - delegate:&coordinator_delegate_ - baseViewController:container_view_controller]; + overlay_coordinator.baseViewController != base_view_controller) { + overlay_coordinator = + [coordinator_factory_ newCoordinatorForRequest:request_ + delegate:&coordinator_delegate_ + baseViewController:base_view_controller]; state->OverlayUIWillBePresented(overlay_coordinator); }
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl_delegate.h b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl_delegate.h new file mode 100644 index 0000000..5f90320 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl_delegate.h
@@ -0,0 +1,24 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_IMPL_DELEGATE_H_ +#define IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_IMPL_DELEGATE_H_ + +#import <Foundation/Foundation.h> + +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h" + +// Delegate protocol used by OverlayPresentationContextImpl to set up the view +// hierarchy to support displaying overlay UI. +@protocol OverlayPresentationContextImplDelegate <NSObject> + +// Instructs the delegate to set up the base UIViewController for overlay UI +// that requires |capababilities| and provide it to |context|. +- (void)updatePresentationContext:(OverlayPresentationContextImpl*)context + forPresentationCapabilities: + (OverlayPresentationContext::UIPresentationCapabilities)capabilities; + +@end + +#endif // IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_IMPL_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl_unittest.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl_unittest.mm new file mode 100644 index 0000000..6b4a4d3 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_impl_unittest.mm
@@ -0,0 +1,364 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h" + +#include "base/bind.h" +#import "base/test/ios/wait_util.h" +#import "ios/chrome/browser/main/test_browser.h" +#include "ios/chrome/browser/overlays/public/overlay_presentation_context_observer.h" +#include "ios/chrome/browser/overlays/public/overlay_request.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_contained_overlay_request_config.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_presented_overlay_request_config.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl_delegate.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_util.h" +#import "ios/chrome/browser/ui/overlays/test/test_overlay_presentation_context.h" +#import "ios/chrome/test/scoped_key_window.h" +#include "ios/web/public/test/web_task_environment.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using base::test::ios::WaitUntilConditionOrTimeout; +using base::test::ios::kWaitForUIElementTimeout; + +@class FakeOverlayPresenationContextDelegate; + +namespace { + +// Mock observer for the presentation context. +class MockOverlayPresentationContextImplObserver + : public OverlayPresentationContextObserver { + public: + MockOverlayPresentationContextImplObserver() {} + ~MockOverlayPresentationContextImplObserver() {} + + MOCK_METHOD2(OverlayPresentationContextWillChangePresentationCapabilities, + void(OverlayPresentationContext*, + OverlayPresentationContext::UIPresentationCapabilities)); + MOCK_METHOD1(OverlayPresentationContextDidChangePresentationCapabilities, + void(OverlayPresentationContext*)); + MOCK_METHOD2(OverlayPresentationContextDidMoveToWindow, + void(OverlayPresentationContext*, UIWindow*)); +}; + +// Returns the presentation capabilities for a context whose contained and +// presented overlay UI support is described by |supports_contained| and +// |supports_presented|. +OverlayPresentationContext::UIPresentationCapabilities GetCapabilities( + bool supports_contained, + bool supports_presented) { + int capabilities = + OverlayPresentationContext::UIPresentationCapabilities::kNone; + if (supports_contained) { + capabilities = + capabilities | + OverlayPresentationContext::UIPresentationCapabilities::kContained; + } + if (supports_presented) { + capabilities = + capabilities | + OverlayPresentationContext::UIPresentationCapabilities::kPresented; + } + return static_cast<OverlayPresentationContext::UIPresentationCapabilities>( + capabilities); +} + +} // namespace + +class OverlayPresentationContextImplTest; + +// Fake delegate to use for tests. +@interface FakeOverlayPresenationContextDelegate + : NSObject <OverlayPresentationContextImplDelegate> +@property(nonatomic, assign) OverlayPresentationContextImplTest* test; +@end + +// Test fixture for OverlayPresentationContextImpl. +class OverlayPresentationContextImplTest : public PlatformTest { + public: + OverlayPresentationContextImplTest() + : browser_(std::make_unique<TestBrowser>()), + context_(browser_.get()), + delegate_([[FakeOverlayPresenationContextDelegate alloc] init]), + root_view_controller_([[UIViewController alloc] init]) { + root_view_controller_.definesPresentationContext = YES; + scoped_window_.Get().rootViewController = root_view_controller_; + delegate_.test = this; + context_.SetDelegate(delegate_); + context_.AddObserver(&observer_); + EXPECT_CALL(observer_, OverlayPresentationContextDidMoveToWindow( + &context_, scoped_window_.Get())); + context_.SetWindow(scoped_window_.Get()); + } + ~OverlayPresentationContextImplTest() override { + context_.RemoveObserver(&observer_); + // The browser needs to be destroyed before |context_| so that observers + // can be unhooked due to BrowserDestroyed(). This is not a problem for + // non-test OverlayPresentationContextImpls since they're owned by the + // Browser and get destroyed after BrowserDestroyed() is called. + browser_ = nullptr; + } + + // Setter for whether the presentation context should support overlay UI + // implemented using child UIViewControllers. + void SetSupportsContainedOverlayUI() { + if (supports_contained_ui_) + return; + + // Updating the support for contained overlay UI will notifiy the observer + // of this change. + EXPECT_CALL(observer_, + OverlayPresentationContextWillChangePresentationCapabilities( + &context_, GetCapabilities(true, supports_presented_ui_))); + EXPECT_CALL( + observer_, + OverlayPresentationContextDidChangePresentationCapabilities(&context_)); + + supports_contained_ui_ = true; + + context_.SetContainerViewController(root_view_controller_); + + // Check that the presentation capabilities have been updated. + ASSERT_EQ(supports_contained_ui_, + OverlayPresentationContextSupportsContainedUI(&context_)); + } + + // Setter for whether the presentation context should support overlay UI + // implemented using presented UIViewControllers. + void SetSupportsPresentedOverlayUI() { + if (supports_presented_ui_) + return; + + // Updating the support for presented overlay UI will notifiy the observer + // of this change. + EXPECT_CALL(observer_, + OverlayPresentationContextWillChangePresentationCapabilities( + &context_, GetCapabilities(supports_contained_ui_, true))); + EXPECT_CALL( + observer_, + OverlayPresentationContextDidChangePresentationCapabilities(&context_)); + + supports_presented_ui_ = true; + + // Present a UIViewController over |root_view_controller_|'s context, then + // supply the view controller to the presentation context. + UIViewController* presentation_context_view_controller = + [[UIViewController alloc] init]; + presentation_context_view_controller.definesPresentationContext = YES; + presentation_context_view_controller.modalPresentationStyle = + UIModalPresentationOverCurrentContext; + __block bool presentation_finished = NO; + [root_view_controller_ + presentViewController:presentation_context_view_controller + animated:NO + completion:^{ + context_.SetPresentationContextViewController( + presentation_context_view_controller); + presentation_finished = YES; + }]; + + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return presentation_finished; + })); + + // Check that the presentation capabilities have been updated. + ASSERT_EQ(supports_presented_ui_, + OverlayPresentationContextSupportsPresentedUI(&context_)); + } + + // Shows the overlay UI for |request| in the context. + void ShowOverlayUI(OverlayRequest* request) { + overlay_presentation_finished_ = false; + overlay_dismissal_finished_ = false; + overlay_dismissal_reason_ = OverlayDismissalReason::kUserInteraction; + context_.ShowOverlayUI(request, base::BindOnce(^{ + overlay_presentation_finished_ = true; + }), + base::BindOnce(^(OverlayDismissalReason reason) { + overlay_dismissal_finished_ = true; + overlay_dismissal_reason_ = reason; + })); + } + + protected: + web::WebTaskEnvironment task_environment_; + std::unique_ptr<TestBrowser> browser_; + TestOverlayPresentationContext context_; + MockOverlayPresentationContextImplObserver observer_; + FakeOverlayPresenationContextDelegate* delegate_ = nil; + ScopedKeyWindow scoped_window_; + UIViewController* root_view_controller_ = nil; + bool overlay_presentation_finished_ = false; + bool overlay_dismissal_finished_ = false; + OverlayDismissalReason overlay_dismissal_reason_ = + OverlayDismissalReason::kUserInteraction; + + private: + // Support for presented or contained UI should only be updated using the + // setters above. + bool supports_contained_ui_ = false; + bool supports_presented_ui_ = false; +}; + +// FakeOverlayPresenationContextDelegate implementation needs to be declared +// after the test fixture so that it can call its public API. +@implementation FakeOverlayPresenationContextDelegate + +- (void)updatePresentationContext:(OverlayPresentationContextImpl*)context + forPresentationCapabilities: + (OverlayPresentationContext::UIPresentationCapabilities)capabilities { + if (capabilities & + OverlayPresentationContext::UIPresentationCapabilities::kContained) { + self.test->SetSupportsContainedOverlayUI(); + } + if (capabilities & + OverlayPresentationContext::UIPresentationCapabilities::kPresented) { + self.test->SetSupportsPresentedOverlayUI(); + } +} + +@end + +// Tests that neither contained nor presented overlay UI can be shown in the +// context if no view controllers have been provided. +TEST_F(OverlayPresentationContextImplTest, NoPresentationCapabilities) { + ASSERT_EQ(context_.GetPresentationCapabilities(), + OverlayPresentationContext::UIPresentationCapabilities::kNone); + + std::unique_ptr<OverlayRequest> contained_request = + OverlayRequest::CreateWithConfig<TestContainedOverlay>(); + EXPECT_FALSE(context_.CanShowUIForRequest(contained_request.get())); + std::unique_ptr<OverlayRequest> presented_request = + OverlayRequest::CreateWithConfig<TestPresentedOverlay>(); + EXPECT_FALSE(context_.CanShowUIForRequest(presented_request.get())); +} + +// Tests that contained overlay UI can be shown if the container +// UIViewController is provided. +TEST_F(OverlayPresentationContextImplTest, ContainedPresentationCapability) { + std::unique_ptr<OverlayRequest> contained_request = + OverlayRequest::CreateWithConfig<TestContainedOverlay>(); + context_.PrepareToShowOverlayUI(contained_request.get()); + EXPECT_TRUE(context_.CanShowUIForRequest(contained_request.get())); + + std::unique_ptr<OverlayRequest> presented_request = + OverlayRequest::CreateWithConfig<TestPresentedOverlay>(); + EXPECT_FALSE(context_.CanShowUIForRequest(presented_request.get())); +} + +// Tests that presented overlay UI can be shown if the presentation context +// UIViewController is provided. +TEST_F(OverlayPresentationContextImplTest, PresentedPresentationCapability) { + std::unique_ptr<OverlayRequest> presented_request = + OverlayRequest::CreateWithConfig<TestPresentedOverlay>(); + context_.PrepareToShowOverlayUI(presented_request.get()); + EXPECT_TRUE(context_.CanShowUIForRequest(presented_request.get())); + + std::unique_ptr<OverlayRequest> contained_request = + OverlayRequest::CreateWithConfig<TestContainedOverlay>(); + EXPECT_FALSE(context_.CanShowUIForRequest(contained_request.get())); +} + +// Tests that CanShowRequest() returns the expected value when the presentation +// capabilities are pass in. +TEST_F(OverlayPresentationContextImplTest, CanShowRequest) { + std::unique_ptr<OverlayRequest> contained_request = + OverlayRequest::CreateWithConfig<TestContainedOverlay>(); + EXPECT_TRUE(context_.CanShowUIForRequest( + contained_request.get(), + OverlayPresentationContext::UIPresentationCapabilities::kContained)); + EXPECT_FALSE(context_.CanShowUIForRequest( + contained_request.get(), + OverlayPresentationContext::UIPresentationCapabilities::kPresented)); + + std::unique_ptr<OverlayRequest> presented_request = + OverlayRequest::CreateWithConfig<TestPresentedOverlay>(); + EXPECT_FALSE(context_.CanShowUIForRequest( + presented_request.get(), + OverlayPresentationContext::UIPresentationCapabilities::kContained)); + EXPECT_TRUE(context_.CanShowUIForRequest( + presented_request.get(), + OverlayPresentationContext::UIPresentationCapabilities::kPresented)); +} + +// Tests the presentation flow for contained overlay UI. +TEST_F(OverlayPresentationContextImplTest, ContainedOverlayUI) { + std::unique_ptr<OverlayRequest> request = + OverlayRequest::CreateWithConfig<TestContainedOverlay>(); + context_.PrepareToShowOverlayUI(request.get()); + ASSERT_EQ(0U, root_view_controller_.view.subviews.count); + ASSERT_EQ(0U, root_view_controller_.childViewControllers.count); + + // Show the UI for |request| and verify that the overlay UI is added to the + // |root_view_controller_|'s view. + ShowOverlayUI(request.get()); + EXPECT_EQ(1U, root_view_controller_.view.subviews.count); + EXPECT_EQ(1U, root_view_controller_.childViewControllers.count); + EXPECT_TRUE(overlay_presentation_finished_); + + // Hide the overlay UI and verify that it was removed from + // |root_view_controller_|'s view. + context_.HideOverlayUI(request.get()); + EXPECT_EQ(0U, root_view_controller_.view.subviews.count); + EXPECT_EQ(0U, root_view_controller_.childViewControllers.count); + EXPECT_TRUE(overlay_dismissal_finished_); + EXPECT_EQ(OverlayDismissalReason::kHiding, overlay_dismissal_reason_); + + // Show the UI again, then cancel it and verify that the view was removed. + ShowOverlayUI(request.get()); + context_.CancelOverlayUI(request.get()); + EXPECT_EQ(0U, root_view_controller_.view.subviews.count); + EXPECT_EQ(0U, root_view_controller_.childViewControllers.count); + EXPECT_TRUE(overlay_dismissal_finished_); + EXPECT_EQ(OverlayDismissalReason::kCancellation, overlay_dismissal_reason_); +} + +// Tests the presentation flow for presented overlay UI. +TEST_F(OverlayPresentationContextImplTest, PresentedOverlayUI) { + std::unique_ptr<OverlayRequest> request = + OverlayRequest::CreateWithConfig<TestPresentedOverlay>(); + context_.PrepareToShowOverlayUI(request.get()); + UIViewController* presentation_base_view_controller = + root_view_controller_.presentedViewController; + ASSERT_TRUE(presentation_base_view_controller); + ASSERT_FALSE(presentation_base_view_controller.presentedViewController); + + // Blocks used to determine when presentation and dismissal is finished. + bool (^presentation_completion_condition)(void) = ^bool { + UIViewController* presented_view_controller = + presentation_base_view_controller.presentedViewController; + return presented_view_controller && + !presented_view_controller.beingPresented && + overlay_presentation_finished_; + }; + bool (^dismissal_completion_condition)(void) = ^bool { + return !presentation_base_view_controller.presentedViewController && + overlay_dismissal_finished_; + }; + + // Show the UI for |request| and verify that the overlay UI is presented over + // |presentation_base_view_controller|. + ShowOverlayUI(request.get()); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, + presentation_completion_condition)); + + // Hide the overlay UI and verify that it was dismissed. + context_.HideOverlayUI(request.get()); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, + dismissal_completion_condition)); + EXPECT_EQ(OverlayDismissalReason::kHiding, overlay_dismissal_reason_); + + // Show the UI again, then cancel it and verify that the view was removed. + ShowOverlayUI(request.get()); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, + presentation_completion_condition)); + context_.CancelOverlayUI(request.get()); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, + dismissal_completion_condition)); + EXPECT_EQ(OverlayDismissalReason::kCancellation, overlay_dismissal_reason_); +}
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_util.h b/ios/chrome/browser/ui/overlays/overlay_presentation_context_util.h new file mode 100644 index 0000000..ed71940 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_util.h
@@ -0,0 +1,20 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_UTIL_H_ +#define IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_UTIL_H_ + +class OverlayPresentationContext; + +// Returns whether |context|'s UIPresentationCapabilities currently support +// overlay UI implemented with contained UIViewControllers. +bool OverlayPresentationContextSupportsContainedUI( + OverlayPresentationContext* context); + +// Returns whether |context|'s UIPresentationCapabilities currently support +// overlay UI implemented with presented UIViewControllers. +bool OverlayPresentationContextSupportsPresentedUI( + OverlayPresentationContext* context); + +#endif // IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_UTIL_H_
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_util.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_util.mm new file mode 100644 index 0000000..4151e657 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_util.mm
@@ -0,0 +1,27 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_util.h" + +#import "ios/chrome/browser/overlays/public/overlay_presentation_context.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +bool OverlayPresentationContextSupportsContainedUI( + OverlayPresentationContext* context) { + if (!context) + return false; + return context->GetPresentationCapabilities() & + OverlayPresentationContext::UIPresentationCapabilities::kContained; +} + +bool OverlayPresentationContextSupportsPresentedUI( + OverlayPresentationContext* context) { + if (!context) + return false; + return context->GetPresentationCapabilities() & + OverlayPresentationContext::UIPresentationCapabilities::kPresented; +}
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller.h b/ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller.h new file mode 100644 index 0000000..8a1b02e8 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller.h
@@ -0,0 +1,15 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_VIEW_CONTROLLER_H_ +#define IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_VIEW_CONTROLLER_H_ + +#import <UIKIt/UIKit.h> + +// View controller that manages the presentation context upon which overlay UI +// is presented. +@interface OverlayPresentationContextViewController : UIViewController +@end + +#endif // IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTEXT_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller.mm new file mode 100644 index 0000000..16f8b78 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller.mm
@@ -0,0 +1,113 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller.h" + +#include "base/logging.h" +#import "base/mac/foundation_util.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_controller.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface OverlayPresentationContextViewController () +// The view used to lay out the presentation context. The presentation context +// view is resized to match |layoutView|'s frame. +@property(nonatomic, readonly) UIView* layoutView; +// Whether the presented view controller is presented using an +// OverlayPresentationController whose |resizesPresentationContainer| property +// returns YES. +@property(nonatomic, readonly) BOOL presentedViewControllerResizesContainer; +@end + +@implementation OverlayPresentationContextViewController + +#pragma mark - Accessors + +- (UIView*)layoutView { + // If there is no overlay UI displayed using presentation or containment, the + // presentation context should be laid out with an empty frame to allow + // touches to pass freely to the underlying browser UI. + UIViewController* presentedViewController = self.presentedViewController; + if (!presentedViewController) + return nil; + + // If overlay UI is displayed using custom UIViewController presentation with + // an OverlayPresentationController that resizes the container view, the + // presentation context should match the presented view's container. + if (self.presentedViewControllerResizesContainer) + return self.presentedViewController.presentationController.containerView; + + // For all other UIViewController presentation, the context should be laid out + // to match the presenter view. + return self.presentingViewController.view; +} + +- (BOOL)presentedViewControllerResizesContainer { + // The non-strict cast returns nil if the presented UIViewController does not + // use an OverlayPresentationController. This results in this selector + // returning NO for these UIViewControllers. + return base::mac::ObjCCast<OverlayPresentationController>( + self.presentedViewController.presentationController) + .resizesPresentationContainer; +} + +#pragma mark - UIViewController + +- (void)viewDidLayoutSubviews { + UIView* view = self.view; + UIView* containerView = self.presentationController.containerView; + UIView* layoutView = self.layoutView; + UIWindow* window = layoutView.window; + CGRect layoutFrame = [window convertRect:layoutView.bounds + fromView:layoutView]; + // Lay out the presentation context and its container view to match + // |layoutView|. + if (layoutView) { + containerView.frame = [containerView.superview convertRect:layoutFrame + fromView:window]; + view.frame = [view.superview convertRect:layoutFrame fromView:window]; + } else { + containerView.frame = CGRectZero; + view.frame = CGRectZero; + } + // If |layoutView| is not laid out using constraints, its frame may have been + // updated by the container and presentation context layout above. Reset the + // frame by converting back from the window coordinates. + if (self.presentedViewControllerResizesContainer && + layoutView.translatesAutoresizingMaskIntoConstraints) { + layoutView.frame = [layoutView.superview convertRect:layoutFrame + fromView:window]; + } +} + +- (void)presentViewController:(UIViewController*)viewController + animated:(BOOL)animated + completion:(void (^)(void))completion { + // Trigger a layout of the presentation context before presenting. This + // allows the presentation context to be resized appropriately during the the + // presentation animation. + [self.view setNeedsLayout]; + + [super presentViewController:viewController + animated:animated + completion:completion]; +} + +- (void)dismissViewControllerAnimated:(BOOL)animated + completion:(void (^)(void))completion { + // Create an updated completion block that triggers layout after the dismissal + // finishes. This will resize the presentation context to CGRectZero so that + // touches can be handled by the underlying browser UI once the presented + // overlay is removed. + [super dismissViewControllerAnimated:animated + completion:^{ + if (completion) + completion(); + [self.view setNeedsLayout]; + }]; +} + +@end
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller_unittest.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller_unittest.mm new file mode 100644 index 0000000..7cf8226 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller_unittest.mm
@@ -0,0 +1,188 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_view_controller.h" + +#import "base/test/ios/wait_util.h" +#import "ios/chrome/browser/main/test_browser.h" +#include "ios/chrome/browser/overlays/public/overlay_request.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_presented_overlay_request_config.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h" +#include "ios/chrome/browser/ui/overlays/test/fake_overlay_request_coordinator_delegate.h" +#import "ios/chrome/browser/ui/overlays/test_modality/test_presented_overlay_coordinator.h" +#import "ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator.h" +#include "ios/chrome/test/scoped_key_window.h" +#include "ios/web/public/test/web_task_environment.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using base::test::ios::WaitUntilConditionOrTimeout; +using base::test::ios::kWaitForUIElementTimeout; + +namespace { +// The frame of resizable presened overlay UI. +const CGRect kWindowFrame = {{100.0, 100.0}, {100.0, 100.0}}; +} // namespace + +// Test fixture for OverlayPresentationContextViewController. +class OverlayPresentationContextViewControllerTest : public PlatformTest { + public: + OverlayPresentationContextViewControllerTest() + : root_view_controller_([[UIViewController alloc] init]), + view_controller_( + [[OverlayPresentationContextViewController alloc] init]) { + root_view_controller_.definesPresentationContext = YES; + scoped_window_.Get().rootViewController = root_view_controller_; + // Present |view_controller_| over |root_view_controller_| without animation + // and wait for the presentation to finish. + view_controller_.modalPresentationStyle = + UIModalPresentationOverCurrentContext; + __block bool presentation_finished = NO; + [root_view_controller_ presentViewController:view_controller_ + animated:NO + completion:^{ + presentation_finished = YES; + }]; + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return presentation_finished; + })); + } + ~OverlayPresentationContextViewControllerTest() override { + // Dismisses |view_controller_| and waits for the dismissal to finish. + __block bool dismissal_finished = NO; + [root_view_controller_ dismissViewControllerAnimated:NO + completion:^{ + dismissal_finished = YES; + }]; + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return dismissal_finished; + })); + } + + protected: + web::WebTaskEnvironment task_environment_; + TestBrowser browser_; + FakeOverlayRequestCoordinatorDelegate delegate_; + ScopedKeyWindow scoped_window_; + UIViewController* root_view_controller_ = nil; + OverlayPresentationContextViewController* view_controller_ = nil; +}; + +// Tests that |view_controller_|'s frame is CGRectZero when there is no overlay +// UI presented upon it. +TEST_F(OverlayPresentationContextViewControllerTest, NoPresentedUI) { + CGRect container_view_frame = + view_controller_.presentationController.containerView.frame; + EXPECT_TRUE(CGRectEqualToRect(container_view_frame, CGRectZero)); + CGRect frame = view_controller_.view.frame; + EXPECT_TRUE(CGRectEqualToRect(frame, CGRectZero)); +} + +// Tests that |view_controller_|'s frame is the same as its presenter while +// showing overlay UI presented over its context. +TEST_F(OverlayPresentationContextViewControllerTest, + PresentedOverCurrentContext) { + // Create a fake overlay coordinator that presents its UI over + // |view_controller_|. + std::unique_ptr<OverlayRequest> request = + OverlayRequest::CreateWithConfig<TestPresentedOverlay>(); + TestPresentedOverlayCoordinator* coordinator = + [[TestPresentedOverlayCoordinator alloc] + initWithBaseViewController:view_controller_ + browser:&browser_ + request:request.get() + delegate:&delegate_]; + + // Start the coordinator and wait for its presentation to finish. + [coordinator startAnimated:NO]; + UIViewController* overlay_view_controller = coordinator.viewController; + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return overlay_view_controller.presentingViewController && + !overlay_view_controller.beingPresented; + })); + + // Verify that the presentation context is resized to + // |root_view_controller_|'s view. + UIView* root_view = root_view_controller_.view; + CGRect root_window_frame = [root_view convertRect:root_view.bounds + toView:nil]; + UIView* container_view = + view_controller_.presentationController.containerView; + EXPECT_TRUE(CGRectEqualToRect( + [container_view convertRect:container_view.bounds toView:nil], + root_window_frame)); + UIView* view = view_controller_.view; + EXPECT_TRUE(CGRectEqualToRect([view convertRect:view.bounds toView:nil], + root_window_frame)); + + // Stop the coordinator and wait for its dismissal to finish. + [coordinator stopAnimated:NO]; + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return !overlay_view_controller.presentingViewController; + })); + + // Verify that the views are resized to CGRectZero when nothing is presented + // upon it. + EXPECT_TRUE(CGRectEqualToRect(container_view.frame, CGRectZero)); + EXPECT_TRUE(CGRectEqualToRect(view.frame, CGRectZero)); +} + +// Tests that |view_controller_|'s frame is the same as its presented view's +// container view if it is shown using custom UIViewController presentation that +// resizes the contianer view. +TEST_F(OverlayPresentationContextViewControllerTest, ResizingPresentedOverlay) { + // Create a fake overlay coordinator that presents its UI over + // |view_controller_| and resizes its presentation container view to + // kWindowFrame. + std::unique_ptr<OverlayRequest> request = + OverlayRequest::CreateWithConfig<TestResizingPresentedOverlay>( + kWindowFrame); + TestResizingPresentedOverlayCoordinator* coordinator = + [[TestResizingPresentedOverlayCoordinator alloc] + initWithBaseViewController:view_controller_ + browser:&browser_ + request:request.get() + delegate:&delegate_]; + + // Start the coordinator and wait for its presentation to finish. + [coordinator startAnimated:NO]; + UIViewController* overlay_view_controller = coordinator.viewController; + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return overlay_view_controller.presentingViewController && + !overlay_view_controller.beingPresented; + })); + + // Verify that the presentation context is resized kWindowFrame. + UIView* container_view = + view_controller_.presentationController.containerView; + EXPECT_TRUE(CGRectEqualToRect( + [container_view convertRect:container_view.bounds toView:nil], + kWindowFrame)); + UIView* view = view_controller_.view; + EXPECT_TRUE(CGRectEqualToRect([view convertRect:view.bounds toView:nil], + kWindowFrame)); + + // Verify that resizing the presentation context container doesn't affect the + // layout of the overlay container. + UIView* overlay_container_view = + overlay_view_controller.presentationController.containerView; + EXPECT_TRUE(CGRectEqualToRect([overlay_container_view convertRect:view.bounds + toView:nil], + kWindowFrame)); + + // Stop the coordinator and wait for its dismissal to finish. + [coordinator stopAnimated:NO]; + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return !overlay_view_controller.presentingViewController; + })); + + // Verify that the views are resized to CGRectZero when nothing is presented + // upon it. + EXPECT_TRUE(CGRectEqualToRect(container_view.frame, CGRectZero)); + EXPECT_TRUE(CGRectEqualToRect(view.frame, CGRectZero)); +}
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_controller.h b/ios/chrome/browser/ui/overlays/overlay_presentation_controller.h new file mode 100644 index 0000000..20cf30db --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_controller.h
@@ -0,0 +1,30 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTROLLER_H_ +#define IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTROLLER_H_ + +#import <UIKit/UIKit.h> + +@protocol OverlayPresentationControllerObserver; + +// Presentation controller used for overlays presented using custom +// UIViewController presentation. +@interface OverlayPresentationController : UIPresentationController + +// Whether the presentation controller resizes the presentation container view. +// When set to YES, the overlay presentation context view will be resized to fit +// the presented view so that touches that fall outside of the overlay can be +// forwarded to the underlying browser UI. Presentation controllers that return +// YES for this property must not lay out their presented views in relation to +// the presenter. Returns NO by default. +@property(nonatomic, readonly) BOOL resizesPresentationContainer; + +// Subclasses must notify the superclass when their container views lay out +// their subviews. +- (void)containerViewWillLayoutSubviews NS_REQUIRES_SUPER; + +@end + +#endif // IOS_CHROME_BROWSER_UI_OVERLAYS_OVERLAY_PRESENTATION_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_controller.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_controller.mm new file mode 100644 index 0000000..c7ca8b8 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_controller.mm
@@ -0,0 +1,33 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/overlay_presentation_controller.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation OverlayPresentationController + +#pragma mark - Accessors + +- (BOOL)resizesPresentationContainer { + return NO; +} + +#pragma mark - UIPresentationController + +- (BOOL)shouldPresentInFullscreen { + return NO; +} + +- (void)containerViewWillLayoutSubviews { + [super containerViewWillLayoutSubviews]; + // Trigger a layout pass for the presenting view controller. This allows the + // presentation context to resize itself to match the presented overlay UI if + // |resizesPresentationContainer| is YES. + [self.presentingViewController.view setNeedsLayout]; +} + +@end
diff --git a/ios/chrome/browser/ui/overlays/test/test_overlay_presentation_context.h b/ios/chrome/browser/ui/overlays/test/test_overlay_presentation_context.h index 71fa9a5..22d3badd 100644 --- a/ios/chrome/browser/ui/overlays/test/test_overlay_presentation_context.h +++ b/ios/chrome/browser/ui/overlays/test/test_overlay_presentation_context.h
@@ -8,6 +8,9 @@ #import "ios/chrome/browser/ui/overlays/overlay_presentation_context_impl.h" // OverlayPresentationContextImpl for OverlayModality::kTesting. +// TODO(crbug.com/1056837): This class is only necessary to prevent the test +// modality code from getting compiled into releases, and can be removed once +// OverlayModality is converted from an enum to a class. class TestOverlayPresentationContext : public OverlayPresentationContextImpl { public: explicit TestOverlayPresentationContext(Browser* browser);
diff --git a/ios/chrome/browser/ui/overlays/test/test_overlay_request_coordinator_factory.h b/ios/chrome/browser/ui/overlays/test/test_overlay_request_coordinator_factory.h index 4d2e808a..ae55a8c8 100644 --- a/ios/chrome/browser/ui/overlays/test/test_overlay_request_coordinator_factory.h +++ b/ios/chrome/browser/ui/overlays/test/test_overlay_request_coordinator_factory.h
@@ -8,6 +8,9 @@ #import "ios/chrome/browser/ui/overlays/overlay_coordinator_factory.h" // OverlayRequestCoordinatorFactory for OverlayModality::kTesting. +// TODO(crbug.com/1056837): This class is only necessary to prevent the test +// modality code from getting compiled into releases, and can be removed once +// OverlayModality is converted from an enum to a class. @interface TestOverlayRequestCoordinatorFactory : OverlayRequestCoordinatorFactory // Initializer for a factory that vends OverlayRequestCoordinators for |browser|
diff --git a/ios/chrome/browser/ui/overlays/test_modality/BUILD.gn b/ios/chrome/browser/ui/overlays/test_modality/BUILD.gn index 4329593..be6d01e 100644 --- a/ios/chrome/browser/ui/overlays/test_modality/BUILD.gn +++ b/ios/chrome/browser/ui/overlays/test_modality/BUILD.gn
@@ -9,6 +9,8 @@ "test_contained_overlay_coordinator.mm", "test_presented_overlay_coordinator.h", "test_presented_overlay_coordinator.mm", + "test_resizing_presented_overlay_coordinator.h", + "test_resizing_presented_overlay_coordinator.mm", ] configs += [ "//build/config/compiler:enable_arc" ] @@ -18,6 +20,7 @@ "//ios/chrome/browser/overlays", "//ios/chrome/browser/overlays/public/test_modality", "//ios/chrome/browser/ui/overlays:coordinators", + "//ios/chrome/browser/ui/overlays:presentation_controller", "//ios/chrome/common/ui/util", ] } @@ -27,6 +30,7 @@ sources = [ "test_contained_overlay_coordinator_unittest.mm", "test_presented_overlay_coordinator_unittest.mm", + "test_resizing_presented_overlay_coordinator_unittest.mm", ] configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator.h b/ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator.h new file mode 100644 index 0000000..ff37a24 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator.h
@@ -0,0 +1,15 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_OVERLAYS_TEST_MODALITY_TEST_RESIZING_PRESENTED_OVERLAY_COORDINATOR_H_ +#define IOS_CHROME_BROWSER_UI_OVERLAYS_TEST_MODALITY_TEST_RESIZING_PRESENTED_OVERLAY_COORDINATOR_H_ + +#import "ios/chrome/browser/ui/overlays/overlay_request_coordinator.h" + +// Coordinator to use in tests for overlay UI supported using presented +// UIViewControllers that resize their presentation container views. +@interface TestResizingPresentedOverlayCoordinator : OverlayRequestCoordinator +@end + +#endif // IOS_CHROME_BROWSER_UI_OVERLAYS_TEST_MODALITY_TEST_RESIZING_PRESENTED_OVERLAY_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator.mm b/ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator.mm new file mode 100644 index 0000000..5c40a54 --- /dev/null +++ b/ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator.mm
@@ -0,0 +1,138 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator.h" + +#import "ios/chrome/browser/overlays/public/test_modality/test_presented_overlay_request_config.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.h" +#import "ios/chrome/browser/ui/overlays/overlay_presentation_controller.h" +#import "ios/chrome/browser/ui/overlays/overlay_request_coordinator+subclassing.h" +#import "ios/chrome/browser/ui/overlays/overlay_request_coordinator_delegate.h" +#import "ios/chrome/common/ui/util/constraints_ui_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#pragma mark - FakeResizingPresentationController + +@interface FakeResizingPresentationController : OverlayPresentationController +// The frame of the presentation container view in window coordinates. +@property(nonatomic, readonly) CGRect windowFrame; +// Initializer for a presentation controller that lays its presentation +// container view with |windowFrame|. +- (instancetype) + initWithPresentedViewController:(UIViewController*)presentedViewController + presentingViewController:(UIViewController*)presentingViewController + windowFrame:(CGRect)windowFrame + NS_DESIGNATED_INITIALIZER; +- (instancetype) + initWithPresentedViewController:(UIViewController*)presentedViewController + presentingViewController:(UIViewController*)presentingViewController + NS_UNAVAILABLE; +@end + +@implementation FakeResizingPresentationController + +- (instancetype) + initWithPresentedViewController:(UIViewController*)presentedViewController + presentingViewController:(UIViewController*)presentingViewController + windowFrame:(CGRect)windowFrame { + if (self = [super initWithPresentedViewController:presentedViewController + presentingViewController:presentingViewController]) { + _windowFrame = windowFrame; + } + return self; +} + +#pragma mark OverlayPresentationController + +- (BOOL)resizesPresentationContainer { + return YES; +} + +#pragma mark UIPresentationController + +- (void)presentationTransitionWillBegin { + [self updateLayout]; +} + +- (void)containerViewWillLayoutSubviews { + [self updateLayout]; + [super containerViewWillLayoutSubviews]; +} + +// Lays out the container view according to the window frame. +- (void)updateLayout { + self.containerView.frame = + [self.containerView.superview convertRect:self.windowFrame fromView:nil]; + self.presentedView.frame = self.containerView.bounds; +} + +@end + +#pragma mark - TestResizingPresentedOverlayCoordinator + +@interface TestResizingPresentedOverlayCoordinator () < + UIViewControllerTransitioningDelegate> +@property(nonatomic, readwrite) UIViewController* presentedViewController; +@end + +@implementation TestResizingPresentedOverlayCoordinator + +#pragma mark OverlayRequestCoordinator + ++ (const OverlayRequestSupport*)requestSupport { + return TestResizingPresentedOverlay::RequestSupport(); +} + +- (UIViewController*)viewController { + return self.presentedViewController; +} + +- (void)startAnimated:(BOOL)animated { + if (self.started) + return; + self.presentedViewController = [[UIViewController alloc] init]; + self.viewController.modalPresentationStyle = UIModalPresentationCustom; + self.viewController.transitioningDelegate = self; + [self.baseViewController + presentViewController:self.viewController + animated:animated + completion:^{ + self.delegate->OverlayUIDidFinishPresentation(self.request); + }]; + self.started = YES; +} + +- (void)stopAnimated:(BOOL)animated { + if (!self.started) + return; + [self.baseViewController + dismissViewControllerAnimated:animated + completion:^{ + self.delegate->OverlayUIDidFinishDismissal( + self.request); + }]; + self.presentedViewController = nil; + self.started = NO; +} + +#pragma mark UIViewControllerTransitioningDelegate + +- (UIPresentationController*) + presentationControllerForPresentedViewController: + (UIViewController*)presented + presentingViewController: + (UIViewController*)presenting + sourceViewController:(UIViewController*)source { + CGRect windowFrame = + self.request->GetConfig<TestResizingPresentedOverlay>()->frame(); + return [[FakeResizingPresentationController alloc] + initWithPresentedViewController:presented + presentingViewController:presenting + windowFrame:windowFrame]; +} + +@end
diff --git a/ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator_unittest.mm b/ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator_unittest.mm new file mode 100644 index 0000000..7c49fac --- /dev/null +++ b/ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator_unittest.mm
@@ -0,0 +1,79 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/overlays/test_modality/test_resizing_presented_overlay_coordinator.h" + +#import "base/test/ios/wait_util.h" +#import "ios/chrome/browser/main/test_browser.h" +#include "ios/chrome/browser/overlays/public/overlay_request.h" +#import "ios/chrome/browser/overlays/public/test_modality/test_resizing_presented_overlay_request_config.h" +#include "ios/chrome/browser/ui/overlays/test/fake_overlay_request_coordinator_delegate.h" +#include "ios/chrome/test/scoped_key_window.h" +#include "ios/web/public/test/web_task_environment.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using base::test::ios::WaitUntilConditionOrTimeout; +using base::test::ios::kWaitForUIElementTimeout; + +namespace { +// The frame of the overlay UI presentation container view in window +// coordinates. +const CGRect kWindowFrame = {{100.0, 100.0}, {100.0, 100.0}}; +} // namespace + +// Test fixture for TestResizingPresentedOverlayCoordinator. +class TestResizingPresentedOverlayCoordinatorTest : public PlatformTest { + public: + TestResizingPresentedOverlayCoordinatorTest() + : root_view_controller_([[UIViewController alloc] init]), + request_(OverlayRequest::CreateWithConfig<TestResizingPresentedOverlay>( + kWindowFrame)), + coordinator_([[TestResizingPresentedOverlayCoordinator alloc] + initWithBaseViewController:root_view_controller_ + browser:&browser_ + request:request_.get() + delegate:&delegate_]) { + scoped_window_.Get().rootViewController = root_view_controller_; + } + + protected: + web::WebTaskEnvironment task_environment_; + TestBrowser browser_; + ScopedKeyWindow scoped_window_; + UIViewController* root_view_controller_ = nil; + std::unique_ptr<OverlayRequest> request_; + FakeOverlayRequestCoordinatorDelegate delegate_; + TestResizingPresentedOverlayCoordinator* coordinator_ = nil; +}; + +// Tests that the coordinator sets up its view correctly. +TEST_F(TestResizingPresentedOverlayCoordinatorTest, ViewSetup) { + // Start the coordinator and wait until the view is finished being presented. + // This is necessary because UIViewController presentation is asynchronous, + // even when performed without animation. + [coordinator_ startAnimated:NO]; + UIViewController* view_controller = coordinator_.viewController; + ASSERT_TRUE(view_controller); + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return view_controller.presentingViewController && + !view_controller.beingPresented; + })); + + // Verify that |coordinator_|'s presentation container view is resized to + // kWindowFrame. + UIView* container_view = view_controller.presentationController.containerView; + CGRect container_view_frame = + [container_view convertRect:container_view.bounds toView:nil]; + EXPECT_TRUE(CGRectEqualToRect(container_view_frame, kWindowFrame)); + + // Stop the coordinator and wait for the dismissal to finish. + [coordinator_ stopAnimated:NO]; + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { + return !view_controller.presentingViewController; + })); +}
diff --git a/ios/chrome/browser/web/navigation_egtest.mm b/ios/chrome/browser/web/navigation_egtest.mm index cab4855..925b8a6 100644 --- a/ios/chrome/browser/web/navigation_egtest.mm +++ b/ios/chrome/browser/web/navigation_egtest.mm
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/ios/ios_util.h" #import "base/test/ios/wait_util.h" #include "components/strings/grit/components_strings.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" @@ -583,6 +584,13 @@ // Tests that navigating forward from NTP works when resuming from session // restore. This is a regression test for https://crbug.com/814790. - (void)testRestoreHistoryToNTPAndNavigateForward { +#if TARGET_IPHONE_SIMULATOR + if (!base::ios::IsRunningOnIOS13OrLater() && ![ChromeEarlGrey isIPadIdiom]) { + // This test is failing on one bot for that very specific configuration. See + // https://crbug.com/1059496 for more info. + EARL_GREY_TEST_DISABLED(@"Failing on iPhone 12 simulator."); + } +#endif GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); const GURL destinationURL = self.testServer->GetURL(kSimpleFileBasedTestURL); [ChromeEarlGrey loadURL:destinationURL]; @@ -603,6 +611,13 @@ // Tests that restoring a placeholder URL is correctly restored. This is a // regression test from http://crbug.com/1011758. - (void)testRestoreHistoryToPlaceholderURL { +#if TARGET_IPHONE_SIMULATOR + if (!base::ios::IsRunningOnIOS13OrLater() && ![ChromeEarlGrey isIPadIdiom]) { + // This test is failing on one bot for that very specific configuration. See + // https://crbug.com/1059496 for more info. + EARL_GREY_TEST_DISABLED(@"Failing on iPhone 12 simulator."); + } +#endif GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); const GURL destinationURL("chrome://crash"); [ChromeEarlGrey loadURL:destinationURL];
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn index cbdb213..d2cfff5 100644 --- a/ios/chrome/test/earl_grey/BUILD.gn +++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -342,7 +342,12 @@ configs += [ "//build/config/compiler:enable_arc" ] testonly = true sources = [ "eg_tests_hook.mm" ] - deps = [ "//ios/chrome/app:tests_hook" ] + deps = [ + "//base", + "//components/policy/core/common:test_support", + "//ios/chrome/app:tests_hook", + "//ios/chrome/browser/policy:test_support", + ] } source_set("eg_app_support+eg2") { @@ -393,6 +398,7 @@ "//ios/chrome/browser/ntp:features", "//ios/chrome/browser/passwords", "//ios/chrome/browser/passwords:eg_app_support+eg2", + "//ios/chrome/browser/policy:eg_app_support+eg2", "//ios/chrome/browser/translate:eg_app_support+eg2", "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/authentication:eg_app_support+eg2",
diff --git a/ios/chrome/test/earl_grey/eg_tests_hook.mm b/ios/chrome/test/earl_grey/eg_tests_hook.mm index 57a3cee..7edf593 100644 --- a/ios/chrome/test/earl_grey/eg_tests_hook.mm +++ b/ios/chrome/test/earl_grey/eg_tests_hook.mm
@@ -4,6 +4,9 @@ #include "ios/chrome/app/tests_hook.h" +#include "base/command_line.h" +#include "ios/chrome/browser/policy/test_platform_policy_provider.h" + #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif @@ -34,6 +37,16 @@ return true; } +policy::ConfigurationPolicyProvider* GetOverriddenPlatformPolicyProvider() { + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + "com.apple.configuration.managed")) { + DVLOG(1) << "Policy data present in NSUserDefaults, not installing test " + "platform provider"; + return nullptr; + } + return GetTestPlatformPolicyProvider(); +} + void SetUpTestsIfPresent() { // No-op for Earl Grey. }
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn index 2aba2c9..0ff1a55b 100644 --- a/ios/chrome/test/earl_grey2/BUILD.gn +++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -58,6 +58,7 @@ "//ios/chrome/browser/net:eg2_tests", "//ios/chrome/browser/ntp_tiles:eg2_tests", "//ios/chrome/browser/passwords:eg2_tests", + "//ios/chrome/browser/policy:eg2_tests", "//ios/chrome/browser/prerender:eg2_tests", "//ios/chrome/browser/translate:eg2_tests", "//ios/chrome/browser/ui/autofill:eg2_tests",
diff --git a/ios/testing/earl_grey/coverage_utils.mm b/ios/testing/earl_grey/coverage_utils.mm index ded91960..02f921b 100644 --- a/ios/testing/earl_grey/coverage_utils.mm +++ b/ios/testing/earl_grey/coverage_utils.mm
@@ -4,15 +4,15 @@ #import "ios/testing/earl_grey/coverage_utils.h" -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #import "testing/coverage_util_ios.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -#if BUILDFLAG(CLANG_COVERAGE) -#include "base/test/clang_coverage.h" +#if BUILDFLAG(CLANG_PROFILING) +#include "base/test/profiling_utils.h" extern "C" void __llvm_profile_reset_counters(void); #endif @@ -23,17 +23,17 @@ } + (void)resetCoverageProfileCounters { -#if BUILDFLAG(CLANG_COVERAGE) +#if BUILDFLAG(CLANG_PROFILING) // In this call, the already-dump flag is also reset, so that the same file // can be dumped to again. __llvm_profile_reset_counters(); -#endif // BUILDFLAG(CLANG_COVERAGE) +#endif // BUILDFLAG(CLANG_PROFILING) } + (void)writeClangCoverageProfile { -#if BUILDFLAG(CLANG_COVERAGE) - base::WriteClangCoverageProfile(); -#endif // BUILDFLAG(CLANG_COVERAGE) +#if BUILDFLAG(CLANG_PROFILING) + base::WriteClangProfilingProfile(); +#endif // BUILDFLAG(CLANG_PROFILING) } @end
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn index f285a72..a94b3d0 100644 --- a/ios/third_party/material_components_ios/BUILD.gn +++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -214,6 +214,7 @@ "src/components/LibraryInfo/src/MDCLibraryInfo.h", "src/components/LibraryInfo/src/MaterialLibraryInfo.h", "src/components/List/src/MDCBaseCell.h", + "src/components/List/src/MDCSelfSizingLayoutAttributes.h", "src/components/List/src/MDCSelfSizingStereoCell.h", "src/components/List/src/MaterialList.h", "src/components/List/src/Theming/MDCBaseCell+MaterialTheming.h", @@ -971,6 +972,7 @@ "src/components/LibraryInfo/src/MaterialLibraryInfo.h", "src/components/List/src/MDCBaseCell.h", "src/components/List/src/MDCBaseCell.m", + "src/components/List/src/MDCSelfSizingLayoutAttributes.h", "src/components/List/src/MDCSelfSizingStereoCell.h", "src/components/List/src/MDCSelfSizingStereoCell.m", "src/components/List/src/MaterialList.h",
diff --git a/media/capture/mojom/BUILD.gn b/media/capture/mojom/BUILD.gn index a2aaecee..bfa974c 100644 --- a/media/capture/mojom/BUILD.gn +++ b/media/capture/mojom/BUILD.gn
@@ -23,24 +23,6 @@ export_header_blink = "third_party/blink/public/platform/web_common.h" } -component("video_capture_mojom_support") { - sources = [ - "video_capture_types_mojom_traits.cc", - "video_capture_types_mojom_traits.h", - ] - public_deps = [ - ":video_capture_shared_cpp_sources", - "//media/base/ipc", - "//media/capture:capture_base", - ] - deps = [ - "//media", - "//media/mojo/mojom", - "//ui/gfx/geometry/mojom:mojom_traits", - ] - defines = [ "IS_MEDIA_CAPTURE_MOJOM_TRAITS_IMPL" ] -} - mojom("image_capture") { sources = [ "image_capture.mojom" ]
diff --git a/media/capture/mojom/video_capture_types.typemap b/media/capture/mojom/video_capture_types.typemap index 39fac0c..bbe592f 100644 --- a/media/capture/mojom/video_capture_types.typemap +++ b/media/capture/mojom/video_capture_types.typemap
@@ -9,8 +9,24 @@ "//media/capture/video/video_capture_device_descriptor.h", "//media/capture/video/video_capture_device_info.h", ] + traits_headers = [ "//media/capture/mojom/video_capture_types_mojom_traits.h" ] -public_deps = [ "//media/capture/mojom:video_capture_mojom_support" ] + +sources = [ + "//media/capture/mojom/video_capture_types_mojom_traits.cc", +] + +deps = [ + "//media", + "//media/capture:capture_base", + "//media/mojo/mojom", + "//ui/gfx/geometry/mojom:mojom_traits", +] + +public_deps = [ + "//media/base/ipc", +] + type_mappings = [ "media.mojom.ResolutionChangePolicy=::media::ResolutionChangePolicy", "media.mojom.PowerLineFrequency=::media::PowerLineFrequency",
diff --git a/media/capture/mojom/video_capture_types_for_blink.typemap b/media/capture/mojom/video_capture_types_for_blink.typemap new file mode 100644 index 0000000..485c4179 --- /dev/null +++ b/media/capture/mojom/video_capture_types_for_blink.typemap
@@ -0,0 +1,32 @@ +# 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. + +mojom = "//media/capture/mojom/video_capture_types.mojom" + +public_headers = [ + "//media/capture/video_capture_types.h", + "//media/capture/video/video_capture_device_descriptor.h", + "//media/capture/video/video_capture_device_info.h", +] + +traits_headers = [ "//media/capture/mojom/video_capture_types_mojom_traits.h" ] + +deps = [ + "//media", + "//media/capture:capture_base", +] + +type_mappings = [ + "media.mojom.ResolutionChangePolicy=::media::ResolutionChangePolicy", + "media.mojom.PowerLineFrequency=::media::PowerLineFrequency", + "media.mojom.VideoCapturePixelFormat=::media::VideoPixelFormat", + "media.mojom.VideoCaptureBufferType=::media::VideoCaptureBufferType", + "media.mojom.VideoCaptureError=::media::VideoCaptureError", + "media.mojom.VideoCaptureFrameDropReason=::media::VideoCaptureFrameDropReason", + "media.mojom.VideoCaptureFormat=::media::VideoCaptureFormat", + "media.mojom.VideoCaptureParams=::media::VideoCaptureParams", + "media.mojom.VideoCaptureDeviceDescriptor=::media::VideoCaptureDeviceDescriptor", + "media.mojom.VideoCaptureDeviceInfo=::media::VideoCaptureDeviceInfo", + "media.mojom.VideoFacingMode=::media::VideoFacingMode", +]
diff --git a/media/capture/mojom/video_capture_types_mojom_traits.h b/media/capture/mojom/video_capture_types_mojom_traits.h index ebe98f62..4dc3b55 100644 --- a/media/capture/mojom/video_capture_types_mojom_traits.h +++ b/media/capture/mojom/video_capture_types_mojom_traits.h
@@ -6,7 +6,7 @@ #define MEDIA_CAPTURE_MOJOM_VIDEO_CAPTURE_TYPES_MOJOM_TRAITS_H_ #include "media/base/video_facing.h" -#include "media/capture/mojom/video_capture_types.mojom-shared.h" +#include "media/capture/mojom/video_capture_types.mojom.h" #include "media/capture/video/video_capture_device_descriptor.h" #include "media/capture/video/video_capture_device_info.h" #include "media/capture/video_capture_types.h" @@ -14,9 +14,8 @@ namespace mojo { template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - EnumTraits<media::mojom::ResolutionChangePolicy, - media::ResolutionChangePolicy> { +struct EnumTraits<media::mojom::ResolutionChangePolicy, + media::ResolutionChangePolicy> { static media::mojom::ResolutionChangePolicy ToMojom( media::ResolutionChangePolicy policy); @@ -25,8 +24,7 @@ }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - EnumTraits<media::mojom::PowerLineFrequency, media::PowerLineFrequency> { +struct EnumTraits<media::mojom::PowerLineFrequency, media::PowerLineFrequency> { static media::mojom::PowerLineFrequency ToMojom( media::PowerLineFrequency frequency); @@ -35,8 +33,8 @@ }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - EnumTraits<media::mojom::VideoCapturePixelFormat, media::VideoPixelFormat> { +struct EnumTraits<media::mojom::VideoCapturePixelFormat, + media::VideoPixelFormat> { static media::mojom::VideoCapturePixelFormat ToMojom( media::VideoPixelFormat input); static bool FromMojom(media::mojom::VideoCapturePixelFormat input, @@ -44,9 +42,8 @@ }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - EnumTraits<media::mojom::VideoCaptureBufferType, - media::VideoCaptureBufferType> { +struct EnumTraits<media::mojom::VideoCaptureBufferType, + media::VideoCaptureBufferType> { static media::mojom::VideoCaptureBufferType ToMojom( media::VideoCaptureBufferType buffer_type); @@ -55,8 +52,7 @@ }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - EnumTraits<media::mojom::VideoCaptureError, media::VideoCaptureError> { +struct EnumTraits<media::mojom::VideoCaptureError, media::VideoCaptureError> { static media::mojom::VideoCaptureError ToMojom( media::VideoCaptureError buffer_type); @@ -65,9 +61,8 @@ }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - EnumTraits<media::mojom::VideoCaptureFrameDropReason, - media::VideoCaptureFrameDropReason> { +struct EnumTraits<media::mojom::VideoCaptureFrameDropReason, + media::VideoCaptureFrameDropReason> { static media::mojom::VideoCaptureFrameDropReason ToMojom( media::VideoCaptureFrameDropReason buffer_type); @@ -76,25 +71,22 @@ }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - EnumTraits<media::mojom::VideoFacingMode, media::VideoFacingMode> { +struct EnumTraits<media::mojom::VideoFacingMode, media::VideoFacingMode> { static media::mojom::VideoFacingMode ToMojom(media::VideoFacingMode input); static bool FromMojom(media::mojom::VideoFacingMode input, media::VideoFacingMode* output); }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi> { +struct EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi> { static media::mojom::VideoCaptureApi ToMojom(media::VideoCaptureApi input); static bool FromMojom(media::mojom::VideoCaptureApi input, media::VideoCaptureApi* output); }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - EnumTraits<media::mojom::VideoCaptureTransportType, - media::VideoCaptureTransportType> { +struct EnumTraits<media::mojom::VideoCaptureTransportType, + media::VideoCaptureTransportType> { static media::mojom::VideoCaptureTransportType ToMojom( media::VideoCaptureTransportType input); static bool FromMojom(media::mojom::VideoCaptureTransportType input, @@ -102,9 +94,8 @@ }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - StructTraits<media::mojom::VideoCaptureFormatDataView, - media::VideoCaptureFormat> { +struct StructTraits<media::mojom::VideoCaptureFormatDataView, + media::VideoCaptureFormat> { static const gfx::Size& frame_size(const media::VideoCaptureFormat& format) { return format.frame_size; } @@ -123,9 +114,8 @@ }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - StructTraits<media::mojom::VideoCaptureParamsDataView, - media::VideoCaptureParams> { +struct StructTraits<media::mojom::VideoCaptureParamsDataView, + media::VideoCaptureParams> { static media::VideoCaptureFormat requested_format( const media::VideoCaptureParams& params) { return params.requested_format; @@ -156,9 +146,8 @@ }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - StructTraits<media::mojom::VideoCaptureDeviceDescriptorDataView, - media::VideoCaptureDeviceDescriptor> { +struct StructTraits<media::mojom::VideoCaptureDeviceDescriptorDataView, + media::VideoCaptureDeviceDescriptor> { static const std::string& display_name( const media::VideoCaptureDeviceDescriptor& input) { return input.display_name(); @@ -194,9 +183,8 @@ }; template <> -struct COMPONENT_EXPORT(MEDIA_CAPTURE_MOJOM_TRAITS) - StructTraits<media::mojom::VideoCaptureDeviceInfoDataView, - media::VideoCaptureDeviceInfo> { +struct StructTraits<media::mojom::VideoCaptureDeviceInfoDataView, + media::VideoCaptureDeviceInfo> { static const media::VideoCaptureDeviceDescriptor& descriptor( const media::VideoCaptureDeviceInfo& input) { return input.descriptor;
diff --git a/printing/BUILD.gn b/printing/BUILD.gn index 2d25b96..1a41207 100644 --- a/printing/BUILD.gn +++ b/printing/BUILD.gn
@@ -329,13 +329,10 @@ if (is_chromeos) { sources += [ "backend/cups_ipp_helper_unittest.cc" ] } else { - sources += [ "backend/cups_helper_unittest.cc" ] - if (is_linux) { - sources += [ "backend/print_backend_cups_linux_unittest.cc" ] - } - if (is_mac) { - sources += [ "backend/print_backend_cups_mac_unittest.cc" ] - } + sources += [ + "backend/cups_helper_unittest.cc", + "backend/print_backend_cups_unittest.cc", + ] } } }
diff --git a/printing/backend/print_backend_cups_linux_unittest.cc b/printing/backend/print_backend_cups_linux_unittest.cc deleted file mode 100644 index ae11eb2..0000000 --- a/printing/backend/print_backend_cups_linux_unittest.cc +++ /dev/null
@@ -1,34 +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 <cups/cups.h> - -#include "printing/backend/print_backend.h" -#include "printing/backend/print_backend_cups.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace printing { - -TEST(PrintBackendCupsLinuxTest, PrinterBasicInfoFromCUPS) { - const char kName[] = "printer"; - cups_dest_t* printer = nullptr; - ASSERT_EQ(1, cupsAddDest(kName, nullptr, 0, &printer)); - - int num_options = 0; - cups_option_t* options = nullptr; - num_options = - cupsAddOption("printer-info", "description", num_options, &options); - printer->num_options = num_options; - printer->options = options; - - PrinterBasicInfo printer_info; - PrintBackendCUPS::PrinterBasicInfoFromCUPS(*printer, &printer_info); - cupsFreeDests(1, printer); - - EXPECT_EQ("printer", printer_info.printer_name); - EXPECT_EQ("printer", printer_info.display_name); - EXPECT_EQ("description", printer_info.printer_description); -} - -} // namespace printing
diff --git a/printing/backend/print_backend_cups_mac_unittest.cc b/printing/backend/print_backend_cups_mac_unittest.cc deleted file mode 100644 index 6732df0..0000000 --- a/printing/backend/print_backend_cups_mac_unittest.cc +++ /dev/null
@@ -1,35 +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 <cups/cups.h> - -#include "printing/backend/print_backend.h" -#include "printing/backend/print_backend_cups.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace printing { - -TEST(PrintBackendCupsMacTest, PrinterBasicInfoFromCUPS) { - const char kName[] = "printer"; - cups_dest_t* printer = nullptr; - ASSERT_EQ(1, cupsAddDest(kName, nullptr, 0, &printer)); - - int num_options = 0; - cups_option_t* options = nullptr; - num_options = cupsAddOption("printer-info", "name", num_options, &options); - num_options = cupsAddOption("printer-make-and-model", "description", - num_options, &options); - printer->num_options = num_options; - printer->options = options; - - PrinterBasicInfo printer_info; - PrintBackendCUPS::PrinterBasicInfoFromCUPS(*printer, &printer_info); - cupsFreeDests(1, printer); - - EXPECT_EQ("printer", printer_info.printer_name); - EXPECT_EQ("name", printer_info.display_name); - EXPECT_EQ("description", printer_info.printer_description); -} - -} // namespace printing
diff --git a/printing/backend/print_backend_cups_unittest.cc b/printing/backend/print_backend_cups_unittest.cc new file mode 100644 index 0000000..aef9f13 --- /dev/null +++ b/printing/backend/print_backend_cups_unittest.cc
@@ -0,0 +1,50 @@ +// Copyright 2020 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 "printing/backend/print_backend_cups.h" + +#include <cups/cups.h> + +#include "build/build_config.h" +#include "printing/backend/print_backend.h" +#include "printing/backend/print_backend_consts.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace printing { + +TEST(PrintBackendCupsTest, PrinterBasicInfoFromCUPS) { + constexpr char kName[] = "printer"; + cups_dest_t* printer = nullptr; + ASSERT_EQ( + 1, cupsAddDest(kName, /*instance=*/nullptr, /*num_dests=*/0, &printer)); + + int num_options = 0; + cups_option_t* options = nullptr; +#if defined(OS_MACOSX) + num_options = + cupsAddOption(kCUPSOptPrinterInfo, "info", num_options, &options); + num_options = cupsAddOption(kCUPSOptPrinterMakeAndModel, "description", + num_options, &options); +#else + num_options = + cupsAddOption(kCUPSOptPrinterInfo, "description", num_options, &options); +#endif + printer->num_options = num_options; + printer->options = options; + + PrinterBasicInfo printer_info; + EXPECT_TRUE( + PrintBackendCUPS::PrinterBasicInfoFromCUPS(*printer, &printer_info)); + cupsFreeDests(/*num_dests=*/1, printer); + + EXPECT_EQ(kName, printer_info.printer_name); +#if defined(OS_MACOSX) + EXPECT_EQ("info", printer_info.display_name); +#else + EXPECT_EQ(kName, printer_info.display_name); +#endif + EXPECT_EQ("description", printer_info.printer_description); +} + +} // namespace printing
diff --git a/remoting/protocol/transport_context.cc b/remoting/protocol/transport_context.cc index 48ee156..e6144e4 100644 --- a/remoting/protocol/transport_context.cc +++ b/remoting/protocol/transport_context.cc
@@ -11,6 +11,7 @@ #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "remoting/base/logging.h" #include "remoting/base/url_request.h" #include "remoting/protocol/port_allocator_factory.h" #include "third_party/webrtc/rtc_base/socket_address.h" @@ -31,6 +32,28 @@ constexpr base::TimeDelta kMinimumIceConfigLifetime = base::TimeDelta::FromHours(1); +void PrintIceConfig(const IceConfig& ice_config) { + HOST_LOG << "Received IceConfig:"; + HOST_LOG << " STUN: ["; + for (auto& stun_server : ice_config.stun_servers) { + HOST_LOG << " " << stun_server.ToString() << ","; + } + HOST_LOG << " ]"; + HOST_LOG << " TURN: ["; + for (auto& turn_server : ice_config.turn_servers) { + HOST_LOG << " {"; + HOST_LOG << " username: " << turn_server.credentials.username; + HOST_LOG << " password: " << turn_server.credentials.password; + for (auto& port : turn_server.ports) { + HOST_LOG << " port: " << port.address.ToString(); + } + HOST_LOG << " },"; + } + HOST_LOG << " ]"; + HOST_LOG << " expiration time: " << ice_config.expiration_time; + HOST_LOG << " max_bitrate_kbps: " << ice_config.max_bitrate_kbps; +} + } // namespace #if !defined(OS_NACL) @@ -81,6 +104,7 @@ // Don't need to make ICE config request if both STUN and Relay are disabled. if ((network_settings_.flags & (NetworkSettings::NAT_TRAVERSAL_STUN | NetworkSettings::NAT_TRAVERSAL_RELAY)) == 0) { + HOST_LOG << "Skipping ICE Config request as STUN and RELAY are disabled"; return; } @@ -108,6 +132,8 @@ ice_config_[relay_mode] = ice_config; ice_config_request_[relay_mode].reset(); + PrintIceConfig(ice_config); + auto& callback_list = pending_ice_config_callbacks_[relay_mode]; while (!callback_list.empty()) { callback_list.begin()->Run(ice_config);
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc index e13fbc3..712f969 100644 --- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc +++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -11,7 +11,7 @@ #include <sys/types.h> #include <unistd.h> -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/logging.h" #include "build/build_config.h" #include "sandbox/linux/bpf_dsl/bpf_dsl.h" @@ -128,7 +128,7 @@ #endif // defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || // defined(MEMORY_SANITIZER) -#if BUILDFLAG(CLANG_COVERAGE_INSIDE_SANDBOX) +#if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) if (SyscallSets::IsPrctl(sysno)) { return Allow(); }
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc index ddf69c49..fc36187c 100644 --- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc +++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -24,7 +24,7 @@ #include <time.h> #include <unistd.h> -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/files/scoped_file.h" #include "base/macros.h" #include "base/posix/eintr_wrapper.h" @@ -345,7 +345,7 @@ #define PR_CAPBSET_READ 23 #endif -#if !BUILDFLAG(CLANG_COVERAGE_INSIDE_SANDBOX) +#if !BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) BPF_DEATH_TEST_C(BaselinePolicy, PrctlSigsys, DEATH_SEGV_MESSAGE(GetPrctlErrorMessageContentForTests()),
diff --git a/testing/android/native_test/native_test_launcher.cc b/testing/android/native_test/native_test_launcher.cc index c66af52b..9fd87ca8 100644 --- a/testing/android/native_test/native_test_launcher.cc +++ b/testing/android/native_test/native_test_launcher.cc
@@ -18,7 +18,7 @@ #include "base/android/scoped_java_ref.h" #include "base/at_exit.h" #include "base/base_switches.h" -#include "base/clang_coverage_buildflags.h" +#include "base/clang_profiling_buildflags.h" #include "base/command_line.h" #include "base/debug/debugger.h" #include "base/files/file_path.h" @@ -33,8 +33,8 @@ #include "testing/android/native_test/native_test_jni_headers/NativeTest_jni.h" #include "testing/android/native_test/native_test_util.h" -#if BUILDFLAG(CLANG_COVERAGE) -#include "base/test/clang_coverage.h" +#if BUILDFLAG(CLANG_PROFILING) +#include "base/test/clang_profiling.h" #endif using base::android::JavaParamRef; @@ -140,9 +140,9 @@ ScopedMainEntryLogger scoped_main_entry_logger; main(argc, &argv[0]); -// Explicitly write coverage data to LLVM profile file. -#if BUILDFLAG(CLANG_COVERAGE) - base::WriteClangCoverageProfile(); +// Explicitly write profiling data to LLVM profile file. +#if BUILDFLAG(CLANG_PROFILING) + base::WriteClangProfilingProfile(); #endif }
diff --git a/testing/buildbot/filters/android.emulator.chrome_public_test_apk.filter b/testing/buildbot/filters/android.emulator.chrome_public_test_apk.filter index 71d1a545..b540cde 100644 --- a/testing/buildbot/filters/android.emulator.chrome_public_test_apk.filter +++ b/testing/buildbot/filters/android.emulator.chrome_public_test_apk.filter
@@ -40,3 +40,6 @@ -org.chromium.chrome.browser.autofill_assistant.AutofillAssistantBottomsheetTest.testNoResize -org.chromium.chrome.browser.autofill_assistant.AutofillAssistantBottomsheetTest.testResizeLayoutViewport -org.chromium.chrome.browser.autofill_assistant.AutofillAssistantBottomsheetTest.testResizeVisualViewport + +# crbug.com/1059046 +-org.chromium.chrome.browser.customtabs.CustomTabFromChromeExternalNavigationTest.testIntentWithRedirectToApp
diff --git a/testing/libfuzzer/fuzzer_test.gni b/testing/libfuzzer/fuzzer_test.gni index 3ad8d15..9674919 100644 --- a/testing/libfuzzer/fuzzer_test.gni +++ b/testing/libfuzzer/fuzzer_test.gni
@@ -24,6 +24,7 @@ # - ubsan_options - UndefinedBehaviorSanitizer options. # - seed_corpus - a directory with seed corpus. # - seed_corpus_deps - dependencies for generating the seed corpus. +# - grammar - defines a grammar used by a grammar based mutator. # # If use_libfuzzer gn flag is defined, then proper fuzzer would be build. # Without use_libfuzzer or use_afl a unit-test style binary would be built on @@ -90,7 +91,7 @@ if (defined(invoker.dict) || defined(invoker.libfuzzer_options) || defined(invoker.asan_options) || defined(invoker.msan_options) || defined(invoker.ubsan_options) || - defined(invoker.environment_variables)) { + defined(invoker.environment_variables) || defined(invoker.grammar)) { if (defined(invoker.dict)) { # Copy dictionary to output. copy(target_name + "_dict_copy") { @@ -142,6 +143,11 @@ args += invoker.environment_variables } + if (defined(invoker.grammar)) { + args += [ "--grammar" ] + args += invoker.grammar + } + outputs = [ "$root_build_dir/$config_file_name" ] } test_deps += [ ":" + config_file_name ]
diff --git a/testing/libfuzzer/gen_fuzzer_config.py b/testing/libfuzzer/gen_fuzzer_config.py index bde9e14..5a0792ba 100755 --- a/testing/libfuzzer/gen_fuzzer_config.py +++ b/testing/libfuzzer/gen_fuzzer_config.py
@@ -40,6 +40,7 @@ parser.add_argument('--asan_options', nargs='+', default=[]) parser.add_argument('--msan_options', nargs='+', default=[]) parser.add_argument('--ubsan_options', nargs='+', default=[]) + parser.add_argument('--grammar', nargs='+', default=[]) parser.add_argument( '--environment_variables', nargs='+', @@ -49,7 +50,8 @@ # Script shouldn't be invoked without any arguments, but just in case. if not (args.dict or args.libfuzzer_options or args.environment_variables or - args.asan_options or args.msan_options or args.ubsan_options): + args.asan_options or args.msan_options or args.ubsan_options or + args.grammar): return config = ConfigParser.ConfigParser() @@ -70,6 +72,9 @@ AddSectionOptions(config, 'ubsan', [option.split('=') for option in args.ubsan_options]) + AddSectionOptions(config, 'grammar', + [option.split('=') for option in args.grammar]) + AddSectionOptions( config, 'env', [option.split('=') for option in args.environment_variables])
diff --git a/testing/scripts/common.py b/testing/scripts/common.py index a948205..f7b34541 100644 --- a/testing/scripts/common.py +++ b/testing/scripts/common.py
@@ -56,11 +56,6 @@ # behavior of the script. parser.add_argument('--args', type=parse_json, default=[]) - parser.add_argument( - '--use-src-side-runtest-py', action='store_true', - help='Use the src-side copy of runtest.py, as opposed to the build-side ' - 'one') - subparsers = parser.add_subparsers() run_parser = subparsers.add_parser('run')
diff --git a/third_party/android_crazy_linker/src/android_linker_testing.md b/third_party/android_crazy_linker/src/android_linker_testing.md index 8c224c29..f38955b 100644 --- a/third_party/android_crazy_linker/src/android_linker_testing.md +++ b/third_party/android_crazy_linker/src/android_linker_testing.md
@@ -4,13 +4,6 @@ versions where dynamic linking is not as advanced. It provides `android_dlopen_ext` functionality, RELRO sharing, compressed relocations, etc. -For crazy reasons outlined in `linker/test_case.py` this linker cannot be tested -using GTest or instrumentation test, hence it also carries a custom testing -framework. The tests are not run as part of CQ, but it is still desirable to run -them before landing changes in code locations listed below. - -Sorry. - These instructions assume [Building Chromium for Android](android_build_instructions.md) as a prerequisite. @@ -23,12 +16,6 @@ base/android/java/src/org/chromium/base/library_loader ``` -The tests themselves are living mostly in these places: -``` -build/android/pylib/linker/test_case.py -content/shell/android -``` - ## Running native tests This will run both unittests and regression tests: @@ -40,16 +27,6 @@ Verbosity of the output can be increased by setting `CRAZY_DEBUG` to 1 in `crazy_linker_debug.h`. -## Running Java Tests - -We recommend running these tests in Release mode, as there are known -complications in testing with the component build. Setting `Linker.DEBUG` to -`true` should also help increase verbosity of the output. -``` -autoninja -C out/Release chromium_linker_test_apk -out/Release/bin/run_chromium_linker_test_apk -``` - ## Fuzzer Tests There are also a few tests for fuzzing the ZIP parser. The instructions to run
diff --git a/third_party/blink/perf_tests/shadow_dom/custom-detail-summary.js b/third_party/blink/perf_tests/shadow_dom/custom-detail-summary.js index 10717e3d..cbf6b47 100644 --- a/third_party/blink/perf_tests/shadow_dom/custom-detail-summary.js +++ b/third_party/blink/perf_tests/shadow_dom/custom-detail-summary.js
@@ -11,7 +11,7 @@ customElements.define("my-detail", class extends HTMLElement { constructor() { super(); - this.attachShadow({ mode: "open", slotting: "manual" }); + this.attachShadow({ mode: "open", slotAssignment: "manual" }); } connectedCallback() { const target = this;
diff --git a/third_party/blink/perf_tests/shadow_dom/declarative-api.html b/third_party/blink/perf_tests/shadow_dom/declarative-api.html index e18cfd9..68481f8 100644 --- a/third_party/blink/perf_tests/shadow_dom/declarative-api.html +++ b/third_party/blink/perf_tests/shadow_dom/declarative-api.html
@@ -4,7 +4,7 @@ </div> <script> const host = document.querySelector("#host"); - const shadow_root = host.attachShadow({ mode: 'open', slotting: 'auto' }); + const shadow_root = host.attachShadow({ mode: 'open', slotAssignment: 'auto' }); const slot1 = document.createElement("slot"); const child1 = document.createElement("child"); shadow_root.appendChild(slot1);
diff --git a/third_party/blink/perf_tests/shadow_dom/imperative-api-appendchild.html b/third_party/blink/perf_tests/shadow_dom/imperative-api-appendchild.html index 18cef3a..ef2aba97 100644 --- a/third_party/blink/perf_tests/shadow_dom/imperative-api-appendchild.html +++ b/third_party/blink/perf_tests/shadow_dom/imperative-api-appendchild.html
@@ -4,7 +4,7 @@ </div> <script> const host = document.querySelector("#host"); - const shadow_root = host.attachShadow({ mode: 'open', slotting: 'manual' }); + const shadow_root = host.attachShadow({ mode: 'open', slotAssignment: 'manual' }); const slot1 = document.createElement("slot"); const child1 = document.createElement("child"); slot1.assign([child1]);
diff --git a/third_party/blink/perf_tests/shadow_dom/imperative-api-assign.html b/third_party/blink/perf_tests/shadow_dom/imperative-api-assign.html index 4c8a1e6d..06417d8 100644 --- a/third_party/blink/perf_tests/shadow_dom/imperative-api-assign.html +++ b/third_party/blink/perf_tests/shadow_dom/imperative-api-assign.html
@@ -4,7 +4,7 @@ </div> <script> const host = document.querySelector("#host"); - const shadow_root = host.attachShadow({ mode: 'open', slotting: 'manual' }); + const shadow_root = host.attachShadow({ mode: 'open', slotAssignment: 'manual' }); const slot1 = document.createElement("slot"); const child1 = document.createElement("child"); shadow_root.appendChild(slot1);
diff --git a/third_party/blink/perf_tests/shadow_dom/imperative-api-assigned-elements.html b/third_party/blink/perf_tests/shadow_dom/imperative-api-assigned-elements.html index 806bc47..6d63ba2 100644 --- a/third_party/blink/perf_tests/shadow_dom/imperative-api-assigned-elements.html +++ b/third_party/blink/perf_tests/shadow_dom/imperative-api-assigned-elements.html
@@ -4,7 +4,7 @@ </div> <script> const host = document.querySelector("#host"); - const shadow_root = host.attachShadow({ mode: 'open', slotting: 'manual' }); + const shadow_root = host.attachShadow({ mode: 'open', slotAssignment: 'manual' }); const slot1 = document.createElement("slot"); const child1 = document.createElement("child"); slot1.assign([child1]);
diff --git a/third_party/blink/perf_tests/shadow_dom/imperative-api-assigned-slot.html b/third_party/blink/perf_tests/shadow_dom/imperative-api-assigned-slot.html index 9ab6794..f77b996e 100644 --- a/third_party/blink/perf_tests/shadow_dom/imperative-api-assigned-slot.html +++ b/third_party/blink/perf_tests/shadow_dom/imperative-api-assigned-slot.html
@@ -4,7 +4,7 @@ </div> <script> const host = document.querySelector("#host"); - const shadow_root = host.attachShadow({ mode: 'open', slotting: 'manual' }); + const shadow_root = host.attachShadow({ mode: 'open', slotAssignment: 'manual' }); const slot1 = document.createElement("slot"); const child1 = document.createElement("child"); slot1.assign([child1]);
diff --git a/third_party/blink/perf_tests/shadow_dom/imperative-api-insertbefore.html b/third_party/blink/perf_tests/shadow_dom/imperative-api-insertbefore.html index 375a36c..7e4882c 100644 --- a/third_party/blink/perf_tests/shadow_dom/imperative-api-insertbefore.html +++ b/third_party/blink/perf_tests/shadow_dom/imperative-api-insertbefore.html
@@ -5,7 +5,7 @@ </div> <script> const host = document.querySelector("#host"); - const shadow_root = host.attachShadow({ mode: 'open', slotting: 'manual' }); + const shadow_root = host.attachShadow({ mode: 'open', slotAssignment: 'manual' }); const slot1 = document.createElement("slot"); const child1 = document.createElement("child"); const child = document.querySelector("#child");
diff --git a/third_party/blink/perf_tests/shadow_dom/imperative-api.html b/third_party/blink/perf_tests/shadow_dom/imperative-api.html index 186a72dd..56ca1c9 100644 --- a/third_party/blink/perf_tests/shadow_dom/imperative-api.html +++ b/third_party/blink/perf_tests/shadow_dom/imperative-api.html
@@ -6,7 +6,7 @@ <script> const host = document.querySelector("#host"); const child1 = document.querySelector("#child1"); - const shadow_root = host.attachShadow({ mode: "open", slotting: "manual" }); + const shadow_root = host.attachShadow({ mode: "open", slotAssignment: "manual" }); window.onload = function() { PerfTestRunner.measureTime({ description: "Measure performance of slot assignment in manual-slotting mode in shadow root.",
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index 82490ead..fced37a4 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2525,6 +2525,8 @@ kQuicTransport = 3184, kQuicTransportStreamApis = 3185, kQuicTransportDatagramApis = 3186, + kV8Document_GetAnimations_Method = 3187, + kV8ShadowRoot_GetAnimations_Method = 3188, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h index 8f319c1..c2c079e5 100644 --- a/third_party/blink/public/web/web_view.h +++ b/third_party/blink/public/web/web_view.h
@@ -238,13 +238,6 @@ // Get the visual viewport's size in CSS pixels. virtual gfx::SizeF VisualViewportSize() const = 0; - // Resizes the unscaled (page scale = 1.0) visual viewport. Normally the - // unscaled visual viewport is the same size as the main frame. The passed - // size becomes the size of the viewport when page scale = 1. This - // is used to shrink the visible viewport to allow things like the ChromeOS - // virtual keyboard to overlay over content but allow scrolling it into view. - virtual void ResizeVisualViewport(const WebSize&) = 0; - // Sets the default minimum, and maximum page scale. These will be overridden // by the page or by the overrides below if they are set. virtual void SetDefaultPageScaleLimits(float min_scale, float max_scale) = 0; @@ -301,19 +294,28 @@ virtual float ZoomFactorForDeviceScaleFactor() = 0; + // This method is used for testing. // Resize the view at the same time as changing the state of the top // controls. If |browser_controls_shrink_layout| is true, the embedder shrunk // the WebView size by the browser controls height. virtual void ResizeWithBrowserControls( - const WebSize&, + const WebSize& main_frame_widget_size, float top_controls_height, float bottom_controls_height, bool browser_controls_shrink_layout) = 0; + // This method is used for testing. + // Resizes the unscaled (page scale = 1.0) visual viewport. Normally the + // unscaled visual viewport is the same size as the main frame. The passed + // size becomes the size of the viewport when page scale = 1. This + // is used to shrink the visible viewport to allow things like the ChromeOS + // virtual keyboard to overlay over content but allow scrolling it into view. + virtual void ResizeVisualViewport(const WebSize&) = 0; // Same as ResizeWithBrowserControls(const WebSize&,float,float,bool), but // includes all browser controls params such as the min heights. virtual void ResizeWithBrowserControls( - const WebSize&, + const WebSize& main_frame_widget_size, + const WebSize& visible_viewport_size, cc::BrowserControlsParams browser_controls_params) = 0; // Same as ResizeWithBrowserControls, but keeps the same BrowserControl
diff --git a/third_party/blink/renderer/bindings/generated_in_core.gni b/third_party/blink/renderer/bindings/generated_in_core.gni index 7f1dd40..5c2451e6 100644 --- a/third_party/blink/renderer/bindings/generated_in_core.gni +++ b/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -107,8 +107,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_selection_mode.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_shadow_root_mode.cc", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_shadow_root_mode.h", - "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_shadow_root_slotting_mode.cc", - "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_shadow_root_slotting_mode.h", + "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_slot_assignment_mode.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_slot_assignment_mode.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_supported_type.cc", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_supported_type.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_text_track_kind.cc",
diff --git a/third_party/blink/renderer/core/animation/animatable.cc b/third_party/blink/renderer/core/animation/animatable.cc index d41b7c8..48505ebb 100644 --- a/third_party/blink/renderer/core/animation/animatable.cc +++ b/third_party/blink/renderer/core/animation/animatable.cc
@@ -105,7 +105,8 @@ return animations; for (const auto& animation : - element->GetDocument().GetDocumentAnimations().getAnimations()) { + element->GetDocument().GetDocumentAnimations().getAnimations( + element->GetTreeScope())) { DCHECK(animation->effect()); // TODO(gtsteel) make this use the idl properties Element* target = To<KeyframeEffect>(animation->effect())->EffectTarget();
diff --git a/third_party/blink/renderer/core/animation/animation_timeline.cc b/third_party/blink/renderer/core/animation/animation_timeline.cc index f6b8996..3a67e258 100644 --- a/third_party/blink/renderer/core/animation/animation_timeline.cc +++ b/third_party/blink/renderer/core/animation/animation_timeline.cc
@@ -63,6 +63,19 @@ return result ? base::make_optional(result->InSecondsF()) : base::nullopt; } +String AnimationTimeline::phase() const { + switch (Phase()) { + case TimelinePhase::kInactive: + return "inactive"; + case TimelinePhase::kBefore: + return "before"; + case TimelinePhase::kActive: + return "active"; + case TimelinePhase::kAfter: + return "after"; + } +} + void AnimationTimeline::ClearOutdatedAnimation(Animation* animation) { DCHECK(!animation->Outdated()); outdated_animation_count_--;
diff --git a/third_party/blink/renderer/core/animation/animation_timeline.h b/third_party/blink/renderer/core/animation/animation_timeline.h index 7654135..1a0a55e 100644 --- a/third_party/blink/renderer/core/animation/animation_timeline.h +++ b/third_party/blink/renderer/core/animation/animation_timeline.h
@@ -14,6 +14,8 @@ class Document; +enum class TimelinePhase { kInactive, kBefore, kActive, kAfter }; + class CORE_EXPORT AnimationTimeline : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); @@ -26,10 +28,12 @@ base::Optional<double> CurrentTime(); base::Optional<double> CurrentTimeSeconds(); + String phase() const; + virtual TimelinePhase Phase() const = 0; + virtual bool IsDocumentTimeline() const { return false; } virtual bool IsScrollTimeline() const { return false; } virtual bool IsActive() const = 0; - virtual String phase() const = 0; // Returns the initial start time for animations that are linked to this // timeline. This method gets invoked when initializing the start time of an // animation on this timeline for the first time. It exists because the
diff --git a/third_party/blink/renderer/core/animation/document_animation.h b/third_party/blink/renderer/core/animation/document_animation.h index dbaf712..0b51df67 100644 --- a/third_party/blink/renderer/core/animation/document_animation.h +++ b/third_party/blink/renderer/core/animation/document_animation.h
@@ -19,10 +19,6 @@ static DocumentTimeline* timeline(Document& document) { return &document.Timeline(); } - - static HeapVector<Member<Animation>> getAnimations(Document& document) { - return document.GetDocumentAnimations().getAnimations(); - } }; } // namespace blink
diff --git a/third_party/blink/renderer/core/animation/document_animation.idl b/third_party/blink/renderer/core/animation/document_animation.idl index abefa7f..7a3eabb0 100644 --- a/third_party/blink/renderer/core/animation/document_animation.idl +++ b/third_party/blink/renderer/core/animation/document_animation.idl
@@ -9,6 +9,4 @@ RuntimeEnabled=WebAnimationsAPI ] partial interface Document { readonly attribute DocumentTimeline timeline; - - sequence<Animation> getAnimations(); };
diff --git a/third_party/blink/renderer/core/animation/document_animations.cc b/third_party/blink/renderer/core/animation/document_animations.cc index 3a68315e..104c0de 100644 --- a/third_party/blink/renderer/core/animation/document_animations.cc +++ b/third_party/blink/renderer/core/animation/document_animations.cc
@@ -121,7 +121,8 @@ timeline->ScheduleNextService(); } -HeapVector<Member<Animation>> DocumentAnimations::getAnimations() { +HeapVector<Member<Animation>> DocumentAnimations::getAnimations( + const TreeScope& tree_scope) { // This method implements the Document::getAnimations method defined in the // web-animations-1 spec. // https://drafts.csswg.org/web-animations-1/#dom-document-getanimations @@ -130,9 +131,9 @@ document_->UpdateStyleAndLayoutTree(); HeapVector<Member<Animation>> animations; if (document_->GetPage()) - animations = document_->GetPage()->Animator().GetAnimations(document_); + animations = document_->GetPage()->Animator().GetAnimations(tree_scope); else - GetAnimationsTargetingDocument(document_, animations); + GetAnimationsTargetingTreeScope(animations, tree_scope); std::sort(animations.begin(), animations.end(), CompareAnimations); return animations; @@ -143,9 +144,9 @@ visitor->Trace(timelines_); } -void DocumentAnimations::GetAnimationsTargetingDocument( - Document* document_, - HeapVector<Member<Animation>>& animations) { +void DocumentAnimations::GetAnimationsTargetingTreeScope( + HeapVector<Member<Animation>>& animations, + const TreeScope& tree_scope) { // This method follows the timelines in a given docmuent and append all the // animations to the reference animations. for (auto& timeline : timelines_) { @@ -156,13 +157,12 @@ !animation->effect()->IsInEffect())) { continue; } - if (auto* effect = DynamicTo<KeyframeEffect>(animation->effect())) { - Element* target = effect->target(); - if (!target || !target->isConnected() || - document_ != target->GetDocument()) { - continue; - } - } + auto* effect = DynamicTo<KeyframeEffect>(animation->effect()); + Element* target = effect->target(); + if (!target || !target->isConnected()) + continue; + if (&tree_scope != &target->GetTreeScope()) + continue; animations.push_back(animation); } }
diff --git a/third_party/blink/renderer/core/animation/document_animations.h b/third_party/blink/renderer/core/animation/document_animations.h index a570ceb..2627b12 100644 --- a/third_party/blink/renderer/core/animation/document_animations.h +++ b/third_party/blink/renderer/core/animation/document_animations.h
@@ -51,8 +51,8 @@ void UpdateAnimationTimingForAnimationFrame(); bool NeedsAnimationTimingUpdate(); void UpdateAnimationTimingIfNeeded(); - void GetAnimationsTargetingDocument(Document*, - HeapVector<Member<Animation>>&); + void GetAnimationsTargetingTreeScope(HeapVector<Member<Animation>>&, + const TreeScope&); // Updates existing animations as part of generating a new (document // lifecycle) frame. Note that this considers and updates state for @@ -61,7 +61,7 @@ DocumentLifecycle::LifecycleState required_lifecycle_state, const PaintArtifactCompositor* paint_artifact_compositor); - HeapVector<Member<Animation>> getAnimations(); + HeapVector<Member<Animation>> getAnimations(const TreeScope&); void Trace(Visitor*); private:
diff --git a/third_party/blink/renderer/core/animation/document_animations_test.cc b/third_party/blink/renderer/core/animation/document_animations_test.cc index 5588947d..c67f99b3 100644 --- a/third_party/blink/renderer/core/animation/document_animations_test.cc +++ b/third_party/blink/renderer/core/animation/document_animations_test.cc
@@ -23,7 +23,7 @@ MockAnimationTimeline(Document* document) : AnimationTimeline(document) {} MOCK_CONST_METHOD0(IsActive, bool()); - MOCK_CONST_METHOD0(phase, String()); + MOCK_CONST_METHOD0(Phase, TimelinePhase()); MOCK_METHOD0(InitialStartTimeForAnimations, base::Optional<base::TimeDelta>()); MOCK_METHOD0(NeedsAnimationTimingUpdate, bool());
diff --git a/third_party/blink/renderer/core/animation/document_timeline.cc b/third_party/blink/renderer/core/animation/document_timeline.cc index 613f486..c6675c40 100644 --- a/third_party/blink/renderer/core/animation/document_timeline.cc +++ b/third_party/blink/renderer/core/animation/document_timeline.cc
@@ -187,11 +187,11 @@ return result; } -String DocumentTimeline::phase() const { +TimelinePhase DocumentTimeline::Phase() const { if (IsActive()) { - return "active"; + return TimelinePhase::kActive; } - return "inactive"; + return TimelinePhase::kInactive; } void DocumentTimeline::PauseAnimationsForTesting(double pause_time) {
diff --git a/third_party/blink/renderer/core/animation/document_timeline.h b/third_party/blink/renderer/core/animation/document_timeline.h index ff6e5cb..c7f8c6d 100644 --- a/third_party/blink/renderer/core/animation/document_timeline.h +++ b/third_party/blink/renderer/core/animation/document_timeline.h
@@ -75,7 +75,7 @@ Animation* Play(AnimationEffect*); bool IsActive() const override; - String phase() const override; + TimelinePhase Phase() const override; base::Optional<base::TimeDelta> InitialStartTimeForAnimations() override; bool HasPendingUpdates() const { return !animations_needing_update_.IsEmpty();
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline.cc b/third_party/blink/renderer/core/animation/scroll_timeline.cc index ac0973c..1d9fa53 100644 --- a/third_party/blink/renderer/core/animation/scroll_timeline.cc +++ b/third_party/blink/renderer/core/animation/scroll_timeline.cc
@@ -145,31 +145,21 @@ return layout_box && layout_box->HasOverflowClip(); } -String ScrollTimeline::phase() const { - // TODO(crbug.com/1046833) - Not yet Implemented - return "inactive"; -} - -// Scroll-linked animations are initialized with the start time of zero. -base::Optional<base::TimeDelta> -ScrollTimeline::InitialStartTimeForAnimations() { - return base::TimeDelta(); -} - -void ScrollTimeline::ScheduleNextService() { - DCHECK_EQ(outdated_animation_count_, 0U); - if (AnimationsNeedingUpdateCount() == 0) - return; - if (CurrentTimeInternal() != last_current_time_internal_) - ScheduleServiceOnNextFrame(); +TimelinePhase ScrollTimeline::Phase() const { + return ComputePhaseAndCurrentTime().phase; } base::Optional<base::TimeDelta> ScrollTimeline::CurrentTimeInternal() { + return ComputePhaseAndCurrentTime().current_time; +} + +ScrollTimeline::PhaseAndTime ScrollTimeline::ComputePhaseAndCurrentTime() + const { // 1. If scroll timeline is inactive, return an unresolved time value. // https://github.com/WICG/scroll-animations/issues/31 // https://wicg.github.io/scroll-animations/#current-time-algorithm if (!IsActive()) { - return base::nullopt; + return {TimelinePhase::kInactive, base::nullopt}; } LayoutBox* layout_box = resolved_scroll_source_->GetLayoutBox(); // 2. Otherwise, let current scroll offset be the current scroll offset of @@ -188,10 +178,10 @@ if (current_offset < resolved_start_scroll_offset) { // Return an unresolved time value if fill is none or forwards. if (fill_ == Timing::FillMode::NONE || fill_ == Timing::FillMode::FORWARDS) - return base::nullopt; + return {TimelinePhase::kBefore, base::nullopt}; // Otherwise, return 0. - return base::TimeDelta(); + return {TimelinePhase::kBefore, base::TimeDelta()}; } // 4. If current scroll offset is greater than or equal to endScrollOffset: @@ -202,26 +192,37 @@ if (resolved_end_scroll_offset < max_offset && (fill_ == Timing::FillMode::NONE || fill_ == Timing::FillMode::BACKWARDS)) { - return base::nullopt; + return {TimelinePhase::kAfter, base::nullopt}; } // Otherwise, return the effective time range. - return base::TimeDelta::FromMillisecondsD(time_range_); - } - - // This is not by the spec, but avoids a negative current time. - // See https://github.com/WICG/scroll-animations/issues/20 - if (resolved_start_scroll_offset >= resolved_end_scroll_offset) { - return base::nullopt; + return {TimelinePhase::kAfter, + base::TimeDelta::FromMillisecondsD(time_range_)}; } // 5. Return the result of evaluating the following expression: // ((current scroll offset - startScrollOffset) / // (endScrollOffset - startScrollOffset)) * effective time range - return base::TimeDelta::FromMillisecondsD( - ((current_offset - resolved_start_scroll_offset) / - (resolved_end_scroll_offset - resolved_start_scroll_offset)) * - time_range_); + base::Optional<base::TimeDelta> calculated_current_time = + base::TimeDelta::FromMillisecondsD( + ((current_offset - resolved_start_scroll_offset) / + (resolved_end_scroll_offset - resolved_start_scroll_offset)) * + time_range_); + return {TimelinePhase::kActive, calculated_current_time}; +} + +// Scroll-linked animations are initialized with the start time of zero. +base::Optional<base::TimeDelta> +ScrollTimeline::InitialStartTimeForAnimations() { + return base::TimeDelta(); +} + +void ScrollTimeline::ScheduleNextService() { + DCHECK_EQ(outdated_animation_count_, 0U); + if (AnimationsNeedingUpdateCount() == 0) + return; + if (CurrentTimeInternal() != last_current_time_internal_) + ScheduleServiceOnNextFrame(); } Element* ScrollTimeline::scrollSource() {
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline.h b/third_party/blink/renderer/core/animation/scroll_timeline.h index 39e8517a4..a359e43 100644 --- a/third_party/blink/renderer/core/animation/scroll_timeline.h +++ b/third_party/blink/renderer/core/animation/scroll_timeline.h
@@ -54,7 +54,7 @@ // have a CSS layout box, or if its layout box is not a scroll container. // https://github.com/WICG/scroll-animations/issues/31 bool IsActive() const override; - String phase() const override; + TimelinePhase Phase() const override; base::Optional<base::TimeDelta> InitialStartTimeForAnimations() override; void ScheduleNextService() override; @@ -102,6 +102,13 @@ Member<Element> scroll_source_; Member<Node> resolved_scroll_source_; + struct PhaseAndTime { + TimelinePhase phase; + base::Optional<base::TimeDelta> current_time; + }; + + PhaseAndTime ComputePhaseAndCurrentTime() const; + ScrollDirection orientation_; Member<CSSPrimitiveValue> start_scroll_offset_; Member<CSSPrimitiveValue> end_scroll_offset_;
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline_test.cc b/third_party/blink/renderer/core/animation/scroll_timeline_test.cc index 432e696..25ac9078 100644 --- a/third_party/blink/renderer/core/animation/scroll_timeline_test.cc +++ b/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
@@ -157,11 +157,74 @@ ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION); bool current_time_is_null = false; - scrollable_area->SetScrollOffset(ScrollOffset(0, 50), + scrollable_area->SetScrollOffset(ScrollOffset(0, 20), mojom::blink::ScrollType::kProgrammatic); + EXPECT_EQ(scroll_timeline->phase(), "before"); scroll_timeline->currentTime(current_time_is_null); EXPECT_TRUE(current_time_is_null); EXPECT_TRUE(scroll_timeline->IsActive()); + + current_time_is_null = false; + scrollable_area->SetScrollOffset(ScrollOffset(0, 60), + mojom::blink::ScrollType::kProgrammatic); + EXPECT_EQ(scroll_timeline->phase(), "before"); + scroll_timeline->currentTime(current_time_is_null); + EXPECT_TRUE(current_time_is_null); + EXPECT_TRUE(scroll_timeline->IsActive()); + + current_time_is_null = false; + scrollable_area->SetScrollOffset(ScrollOffset(0, 100), + mojom::blink::ScrollType::kProgrammatic); + EXPECT_EQ(scroll_timeline->phase(), "after"); + scroll_timeline->currentTime(current_time_is_null); + EXPECT_TRUE(current_time_is_null); + EXPECT_TRUE(scroll_timeline->IsActive()); +} + +TEST_F(ScrollTimelineTest, PhasesAreCorrectWhenUsingOffsets) { + SetBodyInnerHTML(R"HTML( + <style> + #scroller { overflow: scroll; width: 100px; height: 100px; } + #spacer { height: 1000px; } + </style> + <div id='scroller'> + <div id ='spacer'></div> + </div> + )HTML"); + + LayoutBoxModelObject* scroller = + ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller")); + ASSERT_TRUE(scroller); + ASSERT_TRUE(scroller->HasOverflowClip()); + PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea(); + ASSERT_TRUE(scrollable_area); + ScrollTimelineOptions* options = ScrollTimelineOptions::Create(); + DoubleOrScrollTimelineAutoKeyword time_range = + DoubleOrScrollTimelineAutoKeyword::FromDouble(100); + options->setTimeRange(time_range); + options->setScrollSource(GetElementById("scroller")); + options->setStartScrollOffset("10px"); + options->setEndScrollOffset("90px"); + ScrollTimeline* scroll_timeline = + ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION); + + EXPECT_EQ(scroll_timeline->phase(), "before"); + + scrollable_area->SetScrollOffset(ScrollOffset(0, 10), + mojom::blink::ScrollType::kProgrammatic); + EXPECT_EQ(scroll_timeline->phase(), "active"); + + scrollable_area->SetScrollOffset(ScrollOffset(0, 50), + mojom::blink::ScrollType::kProgrammatic); + EXPECT_EQ(scroll_timeline->phase(), "active"); + + scrollable_area->SetScrollOffset(ScrollOffset(0, 90), + mojom::blink::ScrollType::kProgrammatic); + EXPECT_EQ(scroll_timeline->phase(), "after"); + + scrollable_area->SetScrollOffset(ScrollOffset(0, 100), + mojom::blink::ScrollType::kProgrammatic); + EXPECT_EQ(scroll_timeline->phase(), "after"); } TEST_F(ScrollTimelineTest,
diff --git a/third_party/blink/renderer/core/css/vision_deficiency.cc b/third_party/blink/renderer/core/css/vision_deficiency.cc index 66e9d39..5ff98d95 100644 --- a/third_party/blink/renderer/core/css/vision_deficiency.cc +++ b/third_party/blink/renderer/core/css/vision_deficiency.cc
@@ -41,8 +41,7 @@ "0.000 0.000 0.000 1.000 0.000 " "\"/>"); case VisionDeficiency::kBlurredVision: - return CreateFilterDataUrl( - "<feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"2\"/>"); + return CreateFilterDataUrl("<feGaussianBlur stdDeviation=\"2\"/>"); case VisionDeficiency::kDeuteranomaly: return CreateFilterDataUrl( "<feColorMatrix values=\""
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc index b270bc84..990f321 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -148,6 +148,8 @@ void DisplayLockContext::UpdateActivationObservationIfNeeded() { if (!document_) { is_observed_ = false; + is_registered_for_lifecycle_notifications_ = false; + needs_intersection_lock_check_ = false; return; } @@ -165,10 +167,36 @@ document_->RegisterDisplayLockActivationObservation(element_); } else if (!should_observe && is_observed_) { document_->UnregisterDisplayLockActivationObservation(element_); + // We don't need intersection lock checks if we are not observing + // intersections anymore. + needs_intersection_lock_check_ = false; + UpdateLifecycleNotificationRegistration(); } is_observed_ = should_observe; } +bool DisplayLockContext::NeedsLifecycleNotifications() const { + return HasResolver() || needs_intersection_lock_check_; +} + +void DisplayLockContext::UpdateLifecycleNotificationRegistration() { + if (!document_ || !document_->View()) { + is_registered_for_lifecycle_notifications_ = false; + return; + } + + bool needs_notifications = NeedsLifecycleNotifications(); + if (needs_notifications == is_registered_for_lifecycle_notifications_) + return; + + is_registered_for_lifecycle_notifications_ = needs_notifications; + if (needs_notifications) { + document_->View()->RegisterForLifecycleNotifications(this); + } else { + document_->View()->UnregisterFromLifecycleNotifications(this); + } +} + void DisplayLockContext::SetActivatable(uint16_t activatable_mask) { if (IsLocked()) { // If we're locked, the activatable mask might change the activation @@ -193,6 +221,9 @@ update_budget_.reset(); state_ = kLocked; + needs_intersection_lock_check_ = false; + UpdateLifecycleNotificationRegistration(); + // We're no longer activated, so if the signal didn't run yet, we should // cancel it. weak_factory_.InvalidateWeakPtrs(); @@ -283,11 +314,11 @@ void DisplayLockContext::MakeResolver(ScriptState* script_state, Member<ScriptPromiseResolver>* resolver) { DCHECK(ConnectedToView()); - document_->View()->RegisterForLifecycleNotifications(this); *resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); + UpdateLifecycleNotificationRegistration(); } -bool DisplayLockContext::HasResolver() { +bool DisplayLockContext::HasResolver() const { return update_resolver_; } @@ -323,8 +354,7 @@ break; } *resolver = nullptr; - if (!HasResolver() && ConnectedToView()) - document_->View()->UnregisterFromLifecycleNotifications(this); + UpdateLifecycleNotificationRegistration(); } bool DisplayLockContext::ShouldPerformUpdatePhase( @@ -487,6 +517,57 @@ void DisplayLockContext::ClearActivated() { css_is_activated_ = false; + // If we are no longer activated, then we're either committing or acquiring a + // lock. In either case, we don't need to rely on lifecycle observations to + // become hidden. + // TODO(vmpstr): This needs refactoring. + needs_intersection_lock_check_ = false; + UpdateLifecycleNotificationRegistration(); +} + +void DisplayLockContext::NotifyIsIntersectingViewport() { + // If we are now intersecting, then we are definitely not nested in a locked + // subtree and we don't need to lock as a result. + needs_intersection_lock_check_ = false; + UpdateLifecycleNotificationRegistration(); + + if (!IsLocked()) + return; + + DCHECK(IsActivatable(DisplayLockActivationReason::kViewportIntersection)); + CommitForActivationWithSignal( + element_, DisplayLockActivationReason::kViewportIntersection); +} + +void DisplayLockContext::NotifyIsNotIntersectingViewport() { + if (IsLocked()) { + DCHECK(!needs_intersection_lock_check_); + return; + } + + // There are two situations we need to consider here: + // 1. We are off-screen but not nested in any other lock. This means we should + // re-lock (also verify that the reason we're in this state is that we're + // activated). + // 2. We are in a nested locked context. This means we don't actually know + // whether we should lock or not. In order to avoid needless dirty of the + // layout and style trees up to the nested context, we remain unlocked. + // However, we also need to ensure that we relock if we become unnested. + // So, we simply delay this check to the next frame (via LocalFrameView), + // which will call this function again and so we can perform the check + // again. + DCHECK(ConnectedToView()); + auto* locked_ancestor = + DisplayLockUtilities::NearestLockedExclusiveAncestor(*element_); + if (locked_ancestor) { + needs_intersection_lock_check_ = true; + UpdateLifecycleNotificationRegistration(); + } else { + DCHECK(IsActivated()); + ClearActivated(); + StartAcquire(); + DCHECK(!needs_intersection_lock_check_); + } } bool DisplayLockContext::ShouldCommitForActivation( @@ -814,7 +895,7 @@ // Since we're observing the lifecycle updates, ensure that we listen to the // right document's view. - if (HasResolver()) { + if (is_registered_for_lifecycle_notifications_) { if (old_document.View()) old_document.View()->UnregisterFromLifecycleNotifications(this); if (document_->View()) @@ -832,11 +913,28 @@ } void DisplayLockContext::WillStartLifecycleUpdate(const LocalFrameView& view) { + DCHECK(NeedsLifecycleNotifications()); + // If we have an update budget, then forward the call to it, so that it can + // prepare for the lifecycle by propagating the next phase's dirty bits. if (update_budget_) update_budget_->OnLifecycleChange(view.CurrentLifecycleData()); + + // We might have delayed processing intersection observation update (signal + // that we were not intersecting) because this context was nested in another + // locked context. At the start of the lifecycle, we should check whether + // that is still true. In other words, this call will check if we're still + // nested. If we are, we won't do anything. If we're not, then we will lock + // this context. + // + // Note that when we are no longer nested and and we have not received any + // notifications from the intersection observer, it means that we are not + // visible. + if (needs_intersection_lock_check_) + NotifyIsNotIntersectingViewport(); } void DisplayLockContext::DidFinishLifecycleUpdate(const LocalFrameView& view) { + DCHECK(NeedsLifecycleNotifications()); if (state_ == kCommitting) { FinishUpdateResolver(kResolve); state_ = kUnlocked;
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h index 8b44ff1..83c80cd 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context.h +++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -144,6 +144,11 @@ // Clear the activated flag. void ClearActivated(); + // Is called by the intersection observer callback to inform us of the + // intersection state. + void NotifyIsIntersectingViewport(); + void NotifyIsNotIntersectingViewport(); + // Acquire the lock, should only be called when unlocked. void StartAcquire(); // Initiate a commit. @@ -282,10 +287,14 @@ } private: - friend class DisplayLockContextTest; + // Test friends. friend class DisplayLockBudgetTest; - friend class DisplayLockSuspendedHandle; + friend class DisplayLockContextRenderingTest; + friend class DisplayLockContextTest; + + // Production friends. friend class DisplayLockBudget; + friend class DisplayLockSuspendedHandle; class StateChangeHelper { DISALLOW_NEW(); @@ -342,7 +351,7 @@ // Helper functions to resolve the update/commit promises. enum ResolverState { kResolve, kReject, kDetach }; void MakeResolver(ScriptState*, Member<ScriptPromiseResolver>*); - bool HasResolver(); + bool HasResolver() const; void FinishUpdateResolver(ResolverState, const char* reject_reason = nullptr); void FinishResolver(Member<ScriptPromiseResolver>*, ResolverState, @@ -381,6 +390,12 @@ // Scheduled by CommitForActivationWithSignal. void FireActivationEvent(Element* activated_element); + // Determines whether or not we need lifecycle notifications. + bool NeedsLifecycleNotifications() const; + // Updates the lifecycle notification registration based on whether we need + // the notifications. + void UpdateLifecycleNotificationRegistration(); + std::unique_ptr<DisplayLockBudget> update_budget_; Member<ScriptPromiseResolver> update_resolver_; @@ -429,6 +444,17 @@ // valid for CSS version of subtree-visibility. bool css_is_activated_ = false; + // Is set to true if we are registered for lifecycle notifications. + bool is_registered_for_lifecycle_notifications_ = false; + + // This is set to true when we have delayed locking ourselves due to viewport + // intersection (or lack thereof) because we were nested in a locked subtree. + // In that case, we register for lifecycle notifications and check every time + // if we are still nested. + bool needs_intersection_lock_check_ = false; + + // TODO(vmpstr): This is only needed while we're still sending activation + // events. base::WeakPtrFactory<DisplayLockContext> weak_factory_{this}; };
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc index d211278..bfc8ec75 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -1700,6 +1700,10 @@ DisplayLockContextRenderingTest() : RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()), ScopedCSSSubtreeVisibilityHiddenMatchableForTest(true) {} + + bool IsObservingLifecycle(DisplayLockContext* context) const { + return context->is_registered_for_lifecycle_notifications_; + } }; TEST_F(DisplayLockContextRenderingTest, FrameDocumentRemovedWhileAcquire) { @@ -1821,4 +1825,282 @@ EXPECT_EQ(total_count, 4u); } +TEST_F(DisplayLockContextRenderingTest, + NestedLockDoesNotInvalidateOnHideOrShow) { + SetHtmlInnerHTML(R"HTML( + <style> + .auto { subtree-visibility: auto; } + .hidden { subtree-visibility: hidden; } + .item { height: 10px; } + /* this is important to not invalidate layout when we hide the element! */ + #outer { contain: style layout; } + </style> + <div id=outer> + <div id=unrelated> + <div id=inner class=auto>Content</div> + </div> + </div> + )HTML"); + + auto* inner_element = GetDocument().getElementById("inner"); + auto* unrelated_element = GetDocument().getElementById("unrelated"); + auto* outer_element = GetDocument().getElementById("outer"); + + UpdateAllLifecyclePhasesForTest(); + // Intersection observer notifications run as a task. + test::RunPendingTasks(); + + // The intersection observation will unlock inner, which will cause a dirty + // layout bit to be propagated. + EXPECT_TRUE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_TRUE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_TRUE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_TRUE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + // Clear the layout. + UpdateAllLifecyclePhasesForTest(); + EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + // Verify lock state. + auto* inner_context = inner_element->GetDisplayLockContext(); + ASSERT_TRUE(inner_context); + EXPECT_TRUE(inner_context->IsActivated()); + EXPECT_FALSE(inner_context->IsLocked()); + + // Lock outer. + outer_element->setAttribute(html_names::kClassAttr, "hidden"); + // Ensure the lock processes (but don't run intersection observation tasks + // yet). + UpdateAllLifecyclePhasesForTest(); + + // Verify the lock exists. + auto* outer_context = outer_element->GetDisplayLockContext(); + ASSERT_TRUE(outer_context); + EXPECT_TRUE(outer_context->IsLocked()); + + // Everything should be layout clean. + EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + // Inner context should not be observing the lifecycle. + EXPECT_FALSE(IsObservingLifecycle(inner_context)); + + // Run intersection observer notifications. + test::RunPendingTasks(); + + // Run the following checks a few times since we should be observing + // lifecycle. + for (int i = 0; i < 3; ++i) { + // It shouldn't change the fact that we're layout clean. + EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + // Because we skipped hiding the element, inner_context should be observing + // lifecycle. + EXPECT_TRUE(IsObservingLifecycle(inner_context)); + + UpdateAllLifecyclePhasesForTest(); + } + + // Unlock outer. + outer_element->setAttribute(html_names::kClassAttr, ""); + // Ensure the lock processes (but don't run intersection observation tasks + // yet). + UpdateAllLifecyclePhasesForTest(); + + // Note that although we're not nested, we're still observing the lifecycle + // because we don't yet know whether we should or should not hide and we only + // make this decision _before_ the lifecycle actually unlocked outer. + EXPECT_TRUE(IsObservingLifecycle(inner_context)); + + // Verify the lock is gone. + EXPECT_FALSE(outer_context->IsLocked()); + + // Everything should be layout clean. + EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + // Run intersection observer notifications. + test::RunPendingTasks(); + + // We now should know we're visible and so we're not observing the lifecycle. + EXPECT_FALSE(IsObservingLifecycle(inner_context)); + + // Also we should still be activated and unlocked. + EXPECT_TRUE(inner_context->IsActivated()); + EXPECT_FALSE(inner_context->IsLocked()); + + // Everything should be layout clean. + EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); +} + +TEST_F(DisplayLockContextRenderingTest, NestedLockDoesHideWhenItIsOffscreen) { + SetHtmlInnerHTML(R"HTML( + <style> + .auto { subtree-visibility: auto; } + .hidden { subtree-visibility: hidden; } + .item { height: 10px; } + /* this is important to not invalidate layout when we hide the element! */ + #outer { contain: style layout; } + .spacer { height: 10000px; } + </style> + <div id=future_spacer></div> + <div id=outer> + <div id=unrelated> + <div id=inner class=auto>Content</div> + </div> + </div> + )HTML"); + + auto* inner_element = GetDocument().getElementById("inner"); + auto* unrelated_element = GetDocument().getElementById("unrelated"); + auto* outer_element = GetDocument().getElementById("outer"); + + UpdateAllLifecyclePhasesForTest(); + // Intersection observer notifications run as a task. + test::RunPendingTasks(); + + // The intersection observation will unlock inner, which will cause a dirty + // layout bit to be propagated. + EXPECT_TRUE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_TRUE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_TRUE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_TRUE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + // Clear the layout. + UpdateAllLifecyclePhasesForTest(); + EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + // Verify lock state. + auto* inner_context = inner_element->GetDisplayLockContext(); + ASSERT_TRUE(inner_context); + EXPECT_TRUE(inner_context->IsActivated()); + EXPECT_FALSE(inner_context->IsLocked()); + + // Lock outer. + outer_element->setAttribute(html_names::kClassAttr, "hidden"); + // Ensure the lock processes (but don't run intersection observation tasks + // yet). + UpdateAllLifecyclePhasesForTest(); + + // Verify the lock exists. + auto* outer_context = outer_element->GetDisplayLockContext(); + ASSERT_TRUE(outer_context); + EXPECT_TRUE(outer_context->IsLocked()); + + // Everything should be layout clean. + EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + // Inner context should not be observing the lifecycle. + EXPECT_FALSE(IsObservingLifecycle(inner_context)); + + // Run intersection observer notifications. + test::RunPendingTasks(); + + // It shouldn't change the fact that we're layout clean. + EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + // Let future spacer become a real spacer! + GetDocument() + .getElementById("future_spacer") + ->setAttribute(html_names::kClassAttr, "spacer"); + + UpdateAllLifecyclePhasesForTest(); + + // Because we skipped hiding the element, inner_context should be observing + // lifecycle. + EXPECT_TRUE(IsObservingLifecycle(inner_context)); + + // Unlock outer. + outer_element->setAttribute(html_names::kClassAttr, ""); + // Ensure the lock processes (but don't run intersection observation tasks + // yet). + UpdateAllLifecyclePhasesForTest(); + + // Note that although we're not nested, we're still observing the lifecycle + // because we don't yet know whether we should or should not hide and we only + // make this decision _before_ the lifecycle actually unlocked outer. + EXPECT_TRUE(IsObservingLifecycle(inner_context)); + + // Verify the lock is gone. + EXPECT_FALSE(outer_context->IsLocked()); + + // Everything should be layout clean. + EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + // Run intersection observer notifications. + test::RunPendingTasks(); + + // We're still invisible, and we don't know that we're not nested so we're + // still observing the lifecycle. + EXPECT_TRUE(IsObservingLifecycle(inner_context)); + + // We're unlocked for now. + EXPECT_TRUE(inner_context->IsActivated()); + EXPECT_FALSE(inner_context->IsLocked()); + + // Everything should be layout clean. + EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->NeedsLayout()); + EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); + + UpdateAllLifecyclePhasesForTest(); + + // We figured out that we're actually invisible so no need to observe the + // lifecycle. + EXPECT_FALSE(IsObservingLifecycle(inner_context)); + + // We're locked. + EXPECT_FALSE(inner_context->IsActivated()); + EXPECT_TRUE(inner_context->IsLocked()); +} } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 88fb6ee..e7dbc7c 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -8501,21 +8501,9 @@ auto* context = entry->target()->GetDisplayLockContext(); DCHECK(context); if (entry->isIntersecting()) { - if (!context->IsLocked()) - continue; - DCHECK(context->ShouldCommitForActivation( - DisplayLockActivationReason::kViewportIntersection)); - context->CommitForActivationWithSignal( - entry->target(), DisplayLockActivationReason::kViewportIntersection); + context->NotifyIsIntersectingViewport(); } else { - // If we're not visible, but are observing viewport intersections, it - // means that we're either locked (in which case we should remain locked), - // or we've been activated (in which case we should relock). - DCHECK(context->IsLocked() || context->IsActivated()); - if (context->IsLocked()) - continue; - context->ClearActivated(); - context->StartAcquire(); + context->NotifyIsNotIntersectingViewport(); } } }
diff --git a/third_party/blink/renderer/core/dom/document_or_shadow_root.h b/third_party/blink/renderer/core/dom/document_or_shadow_root.h index 6e0427e3..cfed2ae4 100644 --- a/third_party/blink/renderer/core/dom/document_or_shadow_root.h +++ b/third_party/blink/renderer/core/dom/document_or_shadow_root.h
@@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_DOCUMENT_OR_SHADOW_ROOT_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_DOCUMENT_OR_SHADOW_ROOT_H_ +#include "third_party/blink/renderer/core/animation/document_animation.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/shadow_root.h" #include "third_party/blink/renderer/core/frame/web_feature.h" @@ -50,6 +51,15 @@ return tree_scope.GetSelection(); } + static HeapVector<Member<Animation>> getAnimations(Document& document) { + return document.GetDocumentAnimations().getAnimations(document); + } + + static HeapVector<Member<Animation>> getAnimations(ShadowRoot& shadow_root) { + return shadow_root.GetDocument().GetDocumentAnimations().getAnimations( + shadow_root); + } + static Element* elementFromPoint(TreeScope& tree_scope, double x, double y) { return tree_scope.ElementFromPoint(x, y); }
diff --git a/third_party/blink/renderer/core/dom/document_or_shadow_root.idl b/third_party/blink/renderer/core/dom/document_or_shadow_root.idl index f637e1a98..212bde84 100644 --- a/third_party/blink/renderer/core/dom/document_or_shadow_root.idl +++ b/third_party/blink/renderer/core/dom/document_or_shadow_root.idl
@@ -10,6 +10,9 @@ // Selection API // https://w3c.github.io/selection-api/#extensions-to-document-interface [Affects=Nothing] Selection? getSelection(); + // Web-Animation-API + //https://drafts.csswg.org/web-animations/#extensions-to-the-documentorshadowroot-interface-mixin + [RuntimeEnabled=WebAnimationsAPI, Measure] sequence<Animation> getAnimations(); // CSSOM View Module // https://drafts.csswg.org/cssom-view/#extensions-to-the-document-interface Element? elementFromPoint(double x, double y);
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index c3cb3f9..0a353465 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3710,7 +3710,7 @@ DCHECK(!shadow_root_init_dict->hasMode() || !GetShadowRoot()); bool delegates_focus = shadow_root_init_dict->hasDelegatesFocus() && shadow_root_init_dict->delegatesFocus(); - bool manual_slotting = shadow_root_init_dict->slotting() == "manual"; + bool manual_slotting = shadow_root_init_dict->slotAssignment() == "manual"; return &AttachShadowRootInternal(type, delegates_focus, manual_slotting); } @@ -3740,8 +3740,9 @@ GetDocument().SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV1); ShadowRoot& shadow_root = CreateAndAttachShadowRoot(type); shadow_root.SetDelegatesFocus(delegates_focus); - shadow_root.SetSlotting(manual_slotting ? ShadowRootSlotting::kManual - : ShadowRootSlotting::kAuto); + shadow_root.SetSlotAssignmentMode(manual_slotting + ? SlotAssignmentMode::kManual + : SlotAssignmentMode::kAuto); return shadow_root; }
diff --git a/third_party/blink/renderer/core/dom/shadow_root.cc b/third_party/blink/renderer/core/dom/shadow_root.cc index a21966fa..215a8af 100644 --- a/third_party/blink/renderer/core/dom/shadow_root.cc +++ b/third_party/blink/renderer/core/dom/shadow_root.cc
@@ -70,7 +70,7 @@ type_(static_cast<unsigned>(type)), registered_with_parent_shadow_root_(false), delegates_focus_(false), - slotting_(static_cast<unsigned>(ShadowRootSlotting::kAuto)), + slot_assignment_mode_(static_cast<unsigned>(SlotAssignmentMode::kAuto)), needs_distribution_recalc_(false), unused_(0) { if (IsV0()) @@ -108,8 +108,8 @@ return nullptr; } -void ShadowRoot::SetSlotting(ShadowRootSlotting slotting) { - slotting_ = static_cast<unsigned>(slotting); +void ShadowRoot::SetSlotAssignmentMode(SlotAssignmentMode assignment_mode) { + slot_assignment_mode_ = static_cast<unsigned>(assignment_mode); } String ShadowRoot::innerHTML() const {
diff --git a/third_party/blink/renderer/core/dom/shadow_root.h b/third_party/blink/renderer/core/dom/shadow_root.h index 6cdb76d1..edecd12 100644 --- a/third_party/blink/renderer/core/dom/shadow_root.h +++ b/third_party/blink/renderer/core/dom/shadow_root.h
@@ -46,7 +46,7 @@ enum class ShadowRootType { V0, kOpen, kClosed, kUserAgent }; -enum class ShadowRootSlotting { kManual, kAuto }; +enum class SlotAssignmentMode { kManual, kAuto }; class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope { DEFINE_WRAPPERTYPEINFO(); @@ -146,9 +146,16 @@ void SetDelegatesFocus(bool flag) { delegates_focus_ = flag; } bool delegatesFocus() const { return delegates_focus_; } - void SetSlotting(ShadowRootSlotting slotting); - bool IsManualSlotting() { - return slotting_ == static_cast<unsigned>(ShadowRootSlotting::kManual); + void SetSlotAssignmentMode(SlotAssignmentMode assignment); + bool IsManualSlotting() const { + return slot_assignment_mode_ == + static_cast<unsigned>(SlotAssignmentMode::kManual); + } + SlotAssignmentMode GetSlotAssignmentMode() const { + return static_cast<SlotAssignmentMode>(slot_assignment_mode_); + } + String slotAssignment() const { + return IsManualSlotting() ? "manual" : "auto"; } bool ContainsShadowRoots() const { return child_shadow_root_count_; } @@ -181,7 +188,7 @@ unsigned type_ : 2; unsigned registered_with_parent_shadow_root_ : 1; unsigned delegates_focus_ : 1; - unsigned slotting_ : 1; + unsigned slot_assignment_mode_ : 1; unsigned needs_distribution_recalc_ : 1; unsigned unused_ : 10;
diff --git a/third_party/blink/renderer/core/dom/shadow_root.idl b/third_party/blink/renderer/core/dom/shadow_root.idl index d8d12cd..0080770 100644 --- a/third_party/blink/renderer/core/dom/shadow_root.idl +++ b/third_party/blink/renderer/core/dom/shadow_root.idl
@@ -34,6 +34,7 @@ // https://crbug.com/1058762 has been fixed. [CEReactions, CustomElementCallbacks, RaisesException=Setter] attribute [TreatNullAs=EmptyString, StringContext=TrustedHTML] DOMString innerHTML; readonly attribute boolean delegatesFocus; + [RuntimeEnabled=ManualSlotting] readonly attribute SlotAssignmentMode slotAssignment; }; ShadowRoot includes DocumentOrShadowRoot;
diff --git a/third_party/blink/renderer/core/dom/shadow_root_init.idl b/third_party/blink/renderer/core/dom/shadow_root_init.idl index 0857f2a..ed46420 100644 --- a/third_party/blink/renderer/core/dom/shadow_root_init.idl +++ b/third_party/blink/renderer/core/dom/shadow_root_init.idl
@@ -5,10 +5,10 @@ // Spec: https://w3c.github.io/webcomponents/spec/shadow/#shadowrootinit-dictionary enum ShadowRootMode { "open", "closed" }; -enum ShadowRootSlottingMode { "manual", "auto" }; +enum SlotAssignmentMode { "manual", "auto" }; dictionary ShadowRootInit { required ShadowRootMode mode; boolean delegatesFocus; - [RuntimeEnabled=ManualSlotting] ShadowRootSlottingMode slotting; + [RuntimeEnabled=ManualSlotting] SlotAssignmentMode slotAssignment; };
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index ac78c7f3..bcf5d6b 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1258,7 +1258,8 @@ GetPage()->GetVisualViewport().ClampToBoundaries(); } -void WebViewImpl::UpdateICBAndResizeViewport() { +void WebViewImpl::UpdateICBAndResizeViewport( + const IntSize& visible_viewport_size) { // We'll keep the initial containing block size from changing when the top // controls hide so that the ICB will always be the same size as the // viewport with the browser controls shown. @@ -1278,13 +1279,18 @@ .GetViewportDescription()); UpdateMainFrameLayoutSize(); - GetPage()->GetVisualViewport().SetSize(size_); + GetPage()->GetVisualViewport().SetSize(visible_viewport_size); if (MainFrameImpl()->GetFrameView()) { MainFrameImpl()->GetFrameView()->SetInitialViewportSize(icb_size); if (!MainFrameImpl()->GetFrameView()->NeedsLayout()) resize_viewport_anchor_->ResizeFrameView(MainFrameSize()); } + + // The boundaries are not properly established until after the frame view is + // also resized, as demonstrated by + // VisualViewportTest.TestBrowserControlsAdjustmentAndResize. + GetPage()->GetVisualViewport().ClampToBoundaries(); } void WebViewImpl::UpdateBrowserControlsConstraint( @@ -1303,7 +1309,7 @@ constraint == cc::BrowserControlsState::kBoth) || (old_permitted_state == cc::BrowserControlsState::kBoth && constraint == cc::BrowserControlsState::kHidden)) { - UpdateICBAndResizeViewport(); + UpdateICBAndResizeViewport(GetPage()->GetVisualViewport().Size()); } } @@ -1349,7 +1355,9 @@ return GetPage()->GetBrowserControls(); } -void WebViewImpl::ResizeViewWhileAnchored(cc::BrowserControlsParams params) { +void WebViewImpl::ResizeViewWhileAnchored( + cc::BrowserControlsParams params, + const IntSize& visible_viewport_size) { DCHECK(MainFrameImpl()); GetBrowserControls().SetParams(params); @@ -1360,7 +1368,7 @@ TextAutosizer::DeferUpdatePageInfo defer_update_page_info(GetPage()); LocalFrameView* frame_view = MainFrameImpl()->GetFrameView(); IntSize old_size = frame_view->Size(); - UpdateICBAndResizeViewport(); + UpdateICBAndResizeViewport(visible_viewport_size); IntSize new_size = frame_view->Size(); frame_view->MarkViewportConstrainedObjectsForLayout( old_size.Width() != new_size.Width(), @@ -1382,28 +1390,35 @@ float bottom_controls_height, bool browser_controls_shrink_layout) { ResizeWithBrowserControls( - new_size, {top_controls_height, GetBrowserControls().TopMinHeight(), - bottom_controls_height, GetBrowserControls().BottomMinHeight(), - GetBrowserControls().AnimateHeightChanges(), - browser_controls_shrink_layout}); + new_size, new_size, + {top_controls_height, GetBrowserControls().TopMinHeight(), + bottom_controls_height, GetBrowserControls().BottomMinHeight(), + GetBrowserControls().AnimateHeightChanges(), + browser_controls_shrink_layout}); } void WebViewImpl::ResizeWithBrowserControls( - const WebSize& new_size, + const WebSize& main_frame_widget_size, + const WebSize& visible_viewport_size, cc::BrowserControlsParams browser_controls_params) { - if (should_auto_resize_) + if (should_auto_resize_) { + // When auto-resizing only the viewport size comes from the browser, while + // the widget size is determined in the renderer. + ResizeVisualViewport(visible_viewport_size); return; + } - if (size_ == new_size && + if (size_ == main_frame_widget_size && + GetPage()->GetVisualViewport().Size() == IntSize(visible_viewport_size) && GetBrowserControls().Params() == browser_controls_params) return; if (GetPage()->MainFrame() && !GetPage()->MainFrame()->IsLocalFrame()) { // Viewport resize for a remote main frame does not require any // particular action, but the state needs to reflect the correct size - // so that it can be used for initalization if the main frame gets + // so that it can be used for initialization if the main frame gets // swapped to a LocalFrame at a later time. - size_ = new_size; + size_ = main_frame_widget_size; GetPageScaleConstraintsSet().DidChangeInitialContainingBlockSize(size_); GetPage()->GetVisualViewport().SetSize(size_); GetPage()->GetBrowserControls().SetParams(browser_controls_params); @@ -1422,19 +1437,20 @@ bool is_rotation = GetPage()->GetSettings().GetMainFrameResizesAreOrientationChanges() && - size_.width && ContentsSize().Width() && new_size.width != size_.width && + size_.width && ContentsSize().Width() && + main_frame_widget_size.width != size_.width && !fullscreen_controller_->IsFullscreenOrTransitioning(); - size_ = new_size; + size_ = main_frame_widget_size; FloatSize viewport_anchor_coords(viewportAnchorCoordX, viewportAnchorCoordY); if (is_rotation) { RotationViewportAnchor anchor(*view, visual_viewport, viewport_anchor_coords, GetPageScaleConstraintsSet()); - ResizeViewWhileAnchored(browser_controls_params); + ResizeViewWhileAnchored(browser_controls_params, visible_viewport_size); } else { ResizeViewportAnchor::ResizeScope resize_scope(*resize_viewport_anchor_); - ResizeViewWhileAnchored(browser_controls_params); + ResizeViewWhileAnchored(browser_controls_params, visible_viewport_size); } SendResizeEventForMainFrame(); }
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h index 1bf1c68..ea6325c 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.h +++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -136,11 +136,12 @@ void SetDomainRelaxationForbidden(bool, const WebString& scheme) override; void SetWindowFeatures(const WebWindowFeatures&) override; void SetOpenedByDOM() override; - void ResizeWithBrowserControls(const WebSize&, + void ResizeWithBrowserControls(const WebSize& main_frame_widget_size, float top_controls_height, float bottom_controls_height, bool browser_controls_shrink_layout) override; - void ResizeWithBrowserControls(const WebSize&, + void ResizeWithBrowserControls(const WebSize& main_frame_widget_size, + const WebSize& visible_viewport_size, cc::BrowserControlsParams) override; WebFrame* MainFrame() override; WebLocalFrame* FocusedFrame() override; @@ -491,8 +492,9 @@ IntSize ContentsSize() const; void UpdateBrowserControlsConstraint(cc::BrowserControlsState constraint); - void UpdateICBAndResizeViewport(); - void ResizeViewWhileAnchored(cc::BrowserControlsParams params); + void UpdateICBAndResizeViewport(const IntSize& visible_viewport_size); + void ResizeViewWhileAnchored(cc::BrowserControlsParams params, + const IntSize& visible_viewport_size); void UpdateBaseBackgroundColor();
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc index aac8b09c..4696ca2 100644 --- a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc +++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
@@ -1404,6 +1404,28 @@ EXPECT_FALSE(csp->AllowTrustedTypePolicy("somepolicy", true)); } +TEST_F(ContentSecurityPolicyTest, TrustedTypesStarMix) { + csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate()); + csp->DidReceiveHeader("trusted-types abc * def", + ContentSecurityPolicyType::kEnforce, + ContentSecurityPolicySource::kHTTP); + EXPECT_TRUE(csp->AllowTrustedTypePolicy("abc", false)); + EXPECT_TRUE(csp->AllowTrustedTypePolicy("def", false)); + EXPECT_TRUE(csp->AllowTrustedTypePolicy("ghi", false)); + EXPECT_FALSE(csp->AllowTrustedTypePolicy("abc", true)); + EXPECT_FALSE(csp->AllowTrustedTypePolicy("def", true)); + EXPECT_FALSE(csp->AllowTrustedTypePolicy("ghi", true)); +} + +TEST_F(ContentSecurityPolicyTest, TrustedTypeDupe) { + csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate()); + csp->DidReceiveHeader("trusted-types somepolicy 'allow-duplicates'", + ContentSecurityPolicyType::kEnforce, + ContentSecurityPolicySource::kHTTP); + EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false)); + EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true)); +} + TEST_F(ContentSecurityPolicyTest, TrustedTypeDupeStar) { csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate()); csp->DidReceiveHeader("trusted-types * 'allow-duplicates'",
diff --git a/third_party/blink/renderer/core/frame/visual_viewport_test.cc b/third_party/blink/renderer/core/frame/visual_viewport_test.cc index 5b75657..3cd977b 100644 --- a/third_party/blink/renderer/core/frame/visual_viewport_test.cc +++ b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
@@ -238,7 +238,9 @@ // WebView resizes the VisualViewport. TEST_P(VisualViewportTest, TestResize) { InitializeWithDesktopSettings(); - WebView()->MainFrameWidget()->Resize(IntSize(320, 240)); + WebView()->ResizeWithBrowserControls( + IntSize(320, 240), IntSize(320, 240), + WebView()->GetBrowserControls().Params()); NavigateTo("about:blank"); ForceFullCompositingUpdate(); @@ -252,7 +254,8 @@ // Resizing the WebView should change the VisualViewport. web_view_size = IntSize(640, 480); - WebView()->MainFrameWidget()->Resize(web_view_size); + WebView()->ResizeWithBrowserControls( + web_view_size, web_view_size, WebView()->GetBrowserControls().Params()); EXPECT_EQ(web_view_size, IntSize(WebView()->MainFrameWidget()->Size())); EXPECT_EQ(web_view_size, visual_viewport.Size()); @@ -276,7 +279,8 @@ // Vertical scrollbar width and horizontal scrollbar height. IntSize scrollbar_size = IntSize(15, 15); - WebView()->MainFrameWidget()->Resize(size); + WebView()->ResizeWithBrowserControls( + size, size, WebView()->GetBrowserControls().Params()); // Scroll layout viewport and verify visibleContentRect. WebView()->MainFrameImpl()->SetScrollOffset(WebSize(0, 50)); @@ -306,7 +310,9 @@ // make it appear to stay still). This caused bugs like crbug.com/453859. TEST_P(VisualViewportTest, TestResizeAtFullyScrolledPreservesViewportLocation) { InitializeWithDesktopSettings(); - WebView()->MainFrameWidget()->Resize(IntSize(800, 600)); + WebView()->ResizeWithBrowserControls( + IntSize(800, 600), IntSize(800, 600), + WebView()->GetBrowserControls().Params()); RegisterMockedHttpURLLoad("content-width-1000.html"); NavigateTo(base_url_ + "content-width-1000.html"); @@ -332,12 +338,16 @@ // Shrink the WebView, this should cause both viewports to shrink and // WebView should do whatever it needs to do to preserve the visible // location. - WebView()->MainFrameWidget()->Resize(IntSize(700, 550)); + WebView()->ResizeWithBrowserControls( + IntSize(700, 550), IntSize(800, 600), + WebView()->GetBrowserControls().Params()); EXPECT_EQ(expected_location, frame_view.GetScrollableArea()->VisibleContentRect().Location()); - WebView()->MainFrameWidget()->Resize(IntSize(800, 600)); + WebView()->ResizeWithBrowserControls( + IntSize(800, 600), IntSize(800, 600), + WebView()->GetBrowserControls().Params()); EXPECT_EQ(expected_location, frame_view.GetScrollableArea()->VisibleContentRect().Location()); @@ -1450,9 +1460,15 @@ InitializeWithAndroidSettings(); // Initialize with browser controls showing and shrinking the Blink size. + cc::BrowserControlsParams controls; + controls.top_controls_height = browser_controls_height; + controls.browser_controls_shrink_blink_size = true; + // TODO(danakj): The browser (RenderWidgetHostImpl) doesn't shrink the widget + // size by the browser controls, only the visible_viewport_size, but this test + // shrinks and grows both. WebView()->ResizeWithBrowserControls( - WebSize(500, visual_viewport_height - browser_controls_height), 20, 0, - true); + WebSize(500, visual_viewport_height - browser_controls_height), + WebSize(500, visual_viewport_height - browser_controls_height), controls); WebView()->GetBrowserControls().SetShownRatio(1, 0); RegisterMockedHttpURLLoad("content-width-1000.html"); @@ -1493,19 +1509,26 @@ ScrollOffset total_expected = visual_viewport_expected + frame_view_expected; - // Resize the widget to match the browser controls adjustment. Ensure that the - // total offset (i.e. what the user sees) doesn't change because of clamping - // the offsets to valid values. - WebView()->ResizeWithBrowserControls(WebSize(500, visual_viewport_height), 20, - 0, false); + // Resize the widget and visible viewport to match the browser controls + // adjustment. Ensure that the total offset (i.e. what the user sees) doesn't + // change because of clamping the offsets to valid values. + controls.browser_controls_shrink_blink_size = false; + WebView()->ResizeWithBrowserControls(WebSize(500, visual_viewport_height), + WebSize(500, visual_viewport_height), + controls); EXPECT_EQ(IntSize(500, visual_viewport_height), visual_viewport.Size()); EXPECT_EQ(FloatSize(250, visual_viewport_height / page_scale), visual_viewport.VisibleRect().Size()); EXPECT_EQ(IntSize(1000, layout_viewport_height), frame_view.FrameRect().Size()); + EXPECT_EQ(total_expected, visual_viewport.GetScrollOffset() + frame_view.LayoutViewport()->GetScrollOffset()); + + EXPECT_EQ(visual_viewport_expected, visual_viewport.GetScrollOffset()); + EXPECT_EQ(frame_view_expected, + frame_view.LayoutViewport()->GetScrollOffset()); } // Tests that a scroll all the way to the bottom while showing the browser
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc index 6ff2cad1..d8c09436 100644 --- a/third_party/blink/renderer/core/input/event_handler.cc +++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -446,10 +446,10 @@ layout_view->HitTest(location, result); if (LocalFrame* frame = result.InnerNodeFrame()) { - EventHandler::OptionalCursor optional_cursor = + base::Optional<Cursor> optional_cursor = frame->GetEventHandler().SelectCursor(location, result); - if (optional_cursor.IsCursorChange()) { - view->SetCursor(optional_cursor.GetCursor()); + if (optional_cursor.has_value()) { + view->SetCursor(optional_cursor.value()); } } } @@ -493,17 +493,17 @@ return HasEditableStyle(*node); } -EventHandler::OptionalCursor EventHandler::SelectCursor( +base::Optional<Cursor> EventHandler::SelectCursor( const HitTestLocation& location, const HitTestResult& result) { if (scroll_manager_->InResizeMode()) - return kNoCursorChange; + return base::nullopt; Page* page = frame_->GetPage(); if (!page) - return kNoCursorChange; + return base::nullopt; if (scroll_manager_->MiddleClickAutoscrollInProgress()) - return kNoCursorChange; + return base::nullopt; if (result.GetScrollbar() && !result.GetScrollbar()->IsCustomScrollbar()) return PointerCursor(); @@ -543,7 +543,7 @@ case kSetCursor: return override_cursor; case kDoNotSetCursor: - return kNoCursorChange; + return base::nullopt; } } @@ -677,7 +677,7 @@ return PointerCursor(); } -EventHandler::OptionalCursor EventHandler::SelectAutoCursor( +base::Optional<Cursor> EventHandler::SelectAutoCursor( const HitTestResult& result, Node* node, const Cursor& i_beam) { @@ -1061,10 +1061,10 @@ } LocalFrameView* view = frame_->View(); if ((!is_remote_frame || is_portal) && view) { - EventHandler::OptionalCursor optional_cursor = + base::Optional<Cursor> optional_cursor = SelectCursor(mev.GetHitTestLocation(), mev.GetHitTestResult()); - if (optional_cursor.IsCursorChange()) { - view->SetCursor(optional_cursor.GetCursor()); + if (optional_cursor.has_value()) { + view->SetCursor(optional_cursor.value()); } } }
diff --git a/third_party/blink/renderer/core/input/event_handler.h b/third_party/blink/renderer/core/input/event_handler.h index 49caef6..4b8b63eb 100644 --- a/third_party/blink/renderer/core/input/event_handler.h +++ b/third_party/blink/renderer/core/input/event_handler.h
@@ -271,27 +271,6 @@ bool LongTapShouldInvokeContextMenu(); private: - enum NoCursorChangeType { kNoCursorChange }; - - class OptionalCursor { - STACK_ALLOCATED(); - - public: - OptionalCursor(NoCursorChangeType) : is_cursor_change_(false) {} - OptionalCursor(const Cursor& cursor) - : is_cursor_change_(true), cursor_(cursor) {} - - bool IsCursorChange() const { return is_cursor_change_; } - const Cursor& GetCursor() const { - DCHECK(is_cursor_change_); - return cursor_; - } - - private: - bool is_cursor_change_; - Cursor cursor_; - }; - WebInputEventResult HandleMouseMoveOrLeaveEvent( const WebMouseEvent&, const Vector<WebMouseEvent>& coalesced_events, @@ -316,11 +295,11 @@ bool IsSelectingLink(const HitTestResult&); bool ShouldShowIBeamForNode(const Node*, const HitTestResult&); bool ShouldShowResizeForNode(const Node*, const HitTestLocation&); - OptionalCursor SelectCursor(const HitTestLocation& location, - const HitTestResult&); - OptionalCursor SelectAutoCursor(const HitTestResult&, - Node*, - const Cursor& i_beam); + base::Optional<Cursor> SelectCursor(const HitTestLocation& location, + const HitTestResult&); + base::Optional<Cursor> SelectAutoCursor(const HitTestResult&, + Node*, + const Cursor& i_beam); void HoverTimerFired(TimerBase*); void CursorUpdateTimerFired(TimerBase*);
diff --git a/third_party/blink/renderer/core/input/event_handler_test.cc b/third_party/blink/renderer/core/input/event_handler_test.cc index 02bd77a..60eb256 100644 --- a/third_party/blink/renderer/core/input/event_handler_test.cc +++ b/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/optional.h" #include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" @@ -626,7 +627,7 @@ .GetFrame() ->GetEventHandler() .SelectCursor(location, result) - .GetCursor() + .value() .GetType(), ui::mojom::CursorType::kHand); // A hand signals ability to navigate. } @@ -649,7 +650,7 @@ .GetFrame() ->GetEventHandler() .SelectCursor(location, result) - .GetCursor() + .value() .GetType(), ui::mojom::CursorType::kIBeam); // An I-beam signals editability. } @@ -668,7 +669,7 @@ .GetFrame() ->GetEventHandler() .SelectCursor(location, result) - .GetCursor() + .value() .GetType(), // A north-south resize signals vertical resizability. ui::mojom::CursorType::kNorthSouthResize); @@ -688,7 +689,7 @@ .GetFrame() ->GetEventHandler() .SelectCursor(location, result) - .GetCursor() + .value() .GetType(), // An east-west resize signals horizontal resizability. ui::mojom::CursorType::kEastWestResize); @@ -708,7 +709,7 @@ .GetFrame() ->GetEventHandler() .SelectCursor(location, result) - .GetCursor() + .value() .GetType(), // An south-east resize signals both horizontal and // vertical resizability. @@ -730,7 +731,7 @@ .GetFrame() ->GetEventHandler() .SelectCursor(location, result) - .GetCursor() + .value() .GetType(), // An south-west resize signals both horizontal and // vertical resizability when direction is RTL. @@ -754,7 +755,7 @@ .GetFrame() ->GetEventHandler() .SelectCursor(location, result) - .GetCursor() + .value() .GetType(), ui::mojom::CursorType::kSouthEastResize); } @@ -776,7 +777,7 @@ .GetFrame() ->GetEventHandler() .SelectCursor(location, result) - .GetCursor() + .value() .GetType(), ui::mojom::CursorType::kSouthEastResize); }
diff --git a/third_party/blink/renderer/core/page/page_animator.cc b/third_party/blink/renderer/core/page/page_animator.cc index 3a83801..ac2ea15 100644 --- a/third_party/blink/renderer/core/page/page_animator.cc +++ b/third_party/blink/renderer/core/page/page_animator.cc
@@ -182,13 +182,13 @@ } } -HeapVector<Member<Animation>> PageAnimator::GetAnimations(Document* document_) { +HeapVector<Member<Animation>> PageAnimator::GetAnimations( + const TreeScope& tree_scope) { HeapVector<Member<Animation>> animations; DocumentsVector documents = GetAllDocuments(page_->MainFrame()); - for (auto& document : documents) { - document->GetDocumentAnimations().GetAnimationsTargetingDocument( - document_, animations); + document->GetDocumentAnimations().GetAnimationsTargetingTreeScope( + animations, tree_scope); } return animations; }
diff --git a/third_party/blink/renderer/core/page/page_animator.h b/third_party/blink/renderer/core/page/page_animator.h index 0ab0e98d..e32c0ce0 100644 --- a/third_party/blink/renderer/core/page/page_animator.h +++ b/third_party/blink/renderer/core/page/page_animator.h
@@ -17,6 +17,7 @@ class LocalFrame; class Page; +class TreeScope; class CORE_EXPORT PageAnimator final : public GarbageCollected<PageAnimator> { public: @@ -44,7 +45,7 @@ void UpdateLifecycleToLayoutClean(LocalFrame& root_frame, DocumentUpdateReason reason); AnimationClock& Clock() { return animation_clock_; } - HeapVector<Member<Animation>> GetAnimations(Document*); + HeapVector<Member<Animation>> GetAnimations(const TreeScope&); private: void UpdateHitTestOcclusionData(LocalFrame& root_frame);
diff --git a/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc b/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc index 0c261df..6bf94736 100644 --- a/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc +++ b/third_party/blink/renderer/core/page/validation_message_overlay_delegate_test.cc
@@ -78,7 +78,8 @@ To<LocalFrame>(delegate_ptr->GetPageForTesting()->MainFrame()) ->GetDocument(); HeapVector<Member<Animation>> animations = - internal_document->GetDocumentAnimations().getAnimations(); + internal_document->GetDocumentAnimations().getAnimations( + *internal_document); ASSERT_FALSE(animations.IsEmpty()); for (const auto& animation : animations) {
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc index 4c5c2729..f3bd3a4 100644 --- a/third_party/blink/renderer/core/testing/internals.cc +++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -2788,11 +2788,13 @@ StringBuilder result; result.Append("type="); result.Append(CursorTypeToString(cursor.GetType())); - result.Append(" hotSpot="); - result.AppendNumber(cursor.HotSpot().X()); - result.Append(','); - result.AppendNumber(cursor.HotSpot().Y()); - if (cursor.GetImage()) { + if (cursor.GetType() == ui::mojom::CursorType::kCustom) { + result.Append(" hotSpot="); + result.AppendNumber(cursor.HotSpot().X()); + result.Append(','); + result.AppendNumber(cursor.HotSpot().Y()); + + DCHECK(cursor.GetImage()); IntSize size = cursor.GetImage()->Size(); result.Append(" image="); result.AppendNumber(size.Width());
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc b/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc index e29bb484..8c069d2 100644 --- a/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc +++ b/third_party/blink/renderer/core/trustedtypes/trusted_types_util_test.cc
@@ -23,9 +23,6 @@ void TrustedTypesCheckForHTMLThrows(const String& string) { auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); Document& document = dummy_page_holder->GetDocument(); - document.GetContentSecurityPolicy()->DidReceiveHeader( - "trusted-types *", network::mojom::ContentSecurityPolicyType::kEnforce, - network::mojom::ContentSecurityPolicySource::kMeta); V8TestingScope scope; DummyExceptionStateForTesting exception_state; ASSERT_FALSE(exception_state.HadException()); @@ -46,9 +43,6 @@ void TrustedTypesCheckForScriptThrows(const String& string) { auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); Document& document = dummy_page_holder->GetDocument(); - document.GetContentSecurityPolicy()->DidReceiveHeader( - "trusted-types *", network::mojom::ContentSecurityPolicyType::kEnforce, - network::mojom::ContentSecurityPolicySource::kMeta); V8TestingScope scope; DummyExceptionStateForTesting exception_state; ASSERT_FALSE(exception_state.HadException()); @@ -71,9 +65,6 @@ void TrustedTypesCheckForScriptURLThrows(const String& string) { auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); Document& document = dummy_page_holder->GetDocument(); - document.GetContentSecurityPolicy()->DidReceiveHeader( - "trusted-types *", network::mojom::ContentSecurityPolicyType::kEnforce, - network::mojom::ContentSecurityPolicySource::kMeta); V8TestingScope scope; DummyExceptionStateForTesting exception_state; ASSERT_FALSE(exception_state.HadException()); @@ -98,9 +89,6 @@ String expected) { auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600)); Document& document = dummy_page_holder->GetDocument(); - document.GetContentSecurityPolicy()->DidReceiveHeader( - "trusted-types *", network::mojom::ContentSecurityPolicyType::kEnforce, - network::mojom::ContentSecurityPolicySource::kMeta); V8TestingScope scope; DummyExceptionStateForTesting exception_state; String s = TrustedTypesCheckForScript(
diff --git a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc index 9ccc5663..f0e12d8 100644 --- a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc +++ b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
@@ -25,7 +25,8 @@ #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" #include "third_party/webrtc/api/video/i420_buffer.h" #include "third_party/webrtc/api/video/recordable_encoded_frame.h" -#include "third_party/webrtc/rtc_base/time_utils.h" // for TimeMicros +#include "third_party/webrtc/rtc_base/time_utils.h" +#include "third_party/webrtc/system_wrappers/include/clock.h" namespace WTF { @@ -145,6 +146,12 @@ // WebRTC Chromium timestamp diff const base::TimeDelta time_diff_encoded_; + + // WebRTC real time clock, needed to determine NTP offset. + webrtc::Clock* clock_; + + // Offset between NTP clock and WebRTC clock. + const int64_t ntp_offset_; }; MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate:: @@ -163,11 +170,13 @@ base::TimeDelta::FromMicroseconds(rtc::TimeMicros())), start_timestamp_encoded_(media::kNoTimestamp), time_diff_encoded_(base::TimeTicks::Now() - base::TimeTicks() - - base::TimeDelta::FromMicroseconds(rtc::TimeMicros())) { -} + base::TimeDelta::FromMicroseconds(rtc::TimeMicros())), + clock_(webrtc::Clock::GetRealTimeClock()), + ntp_offset_(clock_->TimeInMilliseconds() - + clock_->CurrentNtpInMilliseconds()) {} MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate:: - ~RemoteVideoSourceDelegate() {} + ~RemoteVideoSourceDelegate() = default; void MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate::OnFrame( const webrtc::VideoFrame& incoming_frame) { @@ -301,10 +310,11 @@ // Set capture time to the NTP time, which is the estimated capture time // converted to the local clock. - if (incoming_frame.ntp_time_ms() != 0) { + if (incoming_frame.ntp_time_ms() > 0) { const base::TimeTicks capture_time = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(incoming_frame.ntp_time_ms()) + + base::TimeDelta::FromMilliseconds(incoming_frame.ntp_time_ms() + + ntp_offset_) + time_diff_; video_frame->metadata()->SetTimeTicks( media::VideoFrameMetadata::CAPTURE_BEGIN_TIME, capture_time);
diff --git a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc index 89b73eb..61eb7c4c 100644 --- a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc
@@ -28,6 +28,7 @@ #include "third_party/webrtc/api/rtp_packet_infos.h" #include "third_party/webrtc/api/video/color_space.h" #include "third_party/webrtc/api/video/i420_buffer.h" +#include "third_party/webrtc/system_wrappers/include/clock.h" #include "ui/gfx/color_space.h" namespace blink { @@ -327,6 +328,11 @@ kProcessingFinish - webrtc::TimeDelta::Millis(1.0e3 * kProcessingTime); const webrtc::Timestamp kCaptureTime = kProcessingStart - webrtc::TimeDelta::Millis(20.0); + webrtc::Clock* clock = webrtc::Clock::GetRealTimeClock(); + const int64_t ntp_offset = + clock->CurrentNtpInMilliseconds() - clock->TimeInMilliseconds(); + const webrtc::Timestamp kCaptureTimeNtp = + kCaptureTime + webrtc::TimeDelta::Millis(ntp_offset); // Expected capture time in Chromium epoch. base::TimeTicks kExpectedCaptureTime = base::TimeTicks() + base::TimeDelta::FromMilliseconds(kCaptureTime.ms()) + @@ -348,7 +354,7 @@ webrtc::VideoFrame::Builder() .set_video_frame_buffer(buffer) .set_timestamp_rtp(kRtpTimestamp) - .set_ntp_time_ms(kCaptureTime.ms()) + .set_ntp_time_ms(kCaptureTimeNtp.ms()) .set_packet_infos(webrtc::RtpPacketInfos(packet_infos)) .build();
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc index 6ef6f717..a98b0c8 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -2585,7 +2585,8 @@ if (sender_it == rtp_senders_.end()) { // Create new sender (with empty stream set). sender = MakeGarbageCollected<RTCRtpSender>( - this, std::move(web_sender), kind, track, MediaStreamVector()); + this, std::move(web_sender), kind, track, MediaStreamVector(), + force_encoded_video_insertable_streams()); rtp_senders_.push_back(sender); } else { // Update existing sender (not touching the stream set). @@ -2618,7 +2619,8 @@ if (receiver_it == rtp_receivers_.end()) { // Create new receiver. receiver = MakeGarbageCollected<RTCRtpReceiver>( - this, std::move(platform_receiver), track, MediaStreamVector()); + this, std::move(platform_receiver), track, MediaStreamVector(), + force_encoded_video_insertable_streams()); // Receiving tracks should be muted by default. SetReadyState() propagates // the related state changes to ensure it is muted on all layers. It also // fires events - which is not desired - but because they fire synchronously @@ -2917,7 +2919,8 @@ } DCHECK(FindReceiver(*platform_receiver) == rtp_receivers_.end()); RTCRtpReceiver* rtp_receiver = MakeGarbageCollected<RTCRtpReceiver>( - this, std::move(platform_receiver), track, streams); + this, std::move(platform_receiver), track, streams, + force_encoded_video_insertable_streams()); rtp_receivers_.push_back(rtp_receiver); ScheduleDispatchEvent(MakeGarbageCollected<RTCTrackEvent>( rtp_receiver, rtp_receiver->track(), streams, nullptr));
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc index 574c99f1..cf0f12a3 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
@@ -1871,7 +1871,8 @@ blink::RtpSenderState sender_state = transceiver_state.MoveSenderState(); DCHECK(sender_state.is_initialized()); rtp_senders_.push_back(std::make_unique<blink::RTCRtpSenderImpl>( - native_peer_connection_, track_adapter_map_, std::move(sender_state))); + native_peer_connection_, track_adapter_map_, std::move(sender_state), + force_encoded_video_insertable_streams_)); platform_transceiver = std::make_unique<blink::RTCRtpSenderOnlyTransceiver>( std::make_unique<blink::RTCRtpSenderImpl>(*rtp_senders_.back().get())); } else { @@ -2307,7 +2308,8 @@ blink::RTCRtpReceiverImpl::getId(receiver_state.webrtc_receiver().get()); DCHECK(FindReceiver(receiver_id) == rtp_receivers_.end()); auto rtp_receiver = std::make_unique<blink::RTCRtpReceiverImpl>( - native_peer_connection_, std::move(receiver_state)); + native_peer_connection_, std::move(receiver_state), + force_encoded_video_insertable_streams_); rtp_receivers_.push_back( std::make_unique<blink::RTCRtpReceiverImpl>(*rtp_receiver)); if (peer_connection_tracker_) { @@ -2617,7 +2619,7 @@ // Create a new transceiver, including a sender and a receiver. transceiver = std::make_unique<blink::RTCRtpTransceiverImpl>( native_peer_connection_, track_adapter_map_, - std::move(transceiver_state)); + std::move(transceiver_state), force_encoded_video_insertable_streams_); rtp_transceivers_.push_back(transceiver->ShallowCopy()); DCHECK(FindSender(blink::RTCRtpSenderImpl::getId(webrtc_sender.get())) == rtp_senders_.end());
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc index 3447f49..de828dab 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc
@@ -13,13 +13,20 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_header_extension_capability.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_header_extension_parameters.h" #include "third_party/blink/renderer/core/loader/document_loader.h" +#include "third_party/blink/renderer/core/streams/readable_stream.h" +#include "third_party/blink/renderer/core/streams/writable_stream.h" #include "third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_insertable_streams.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_stats_report.h" #include "third_party/blink/renderer/modules/peerconnection/web_rtc_stats_report_callback_resolver.h" #include "third_party/blink/renderer/platform/bindings/microtask.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" +#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_video_stream_transformer.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_stats.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -30,13 +37,19 @@ RTCRtpReceiver::RTCRtpReceiver(RTCPeerConnection* pc, std::unique_ptr<RTCRtpReceiverPlatform> receiver, MediaStreamTrack* track, - MediaStreamVector streams) + MediaStreamVector streams, + bool force_encoded_video_insertable_streams) : pc_(pc), receiver_(std::move(receiver)), track_(track), - streams_(std::move(streams)) { + streams_(std::move(streams)), + force_encoded_video_insertable_streams_( + force_encoded_video_insertable_streams) { + DCHECK(pc_); DCHECK(receiver_); DCHECK(track_); + if (force_encoded_video_insertable_streams_) + RegisterEncodedVideoStreamCallback(); } MediaStreamTrack* RTCRtpReceiver::track() const { @@ -145,9 +158,20 @@ RTCInsertableStreams* RTCRtpReceiver::createEncodedVideoStreams( ScriptState* script_state, ExceptionState& exception_state) { - exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, - "Not supported"); - return nullptr; + if (!force_encoded_video_insertable_streams_) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Encoded video streams not requested at PC initialization"); + return nullptr; + } + if (encoded_video_streams_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "Encoded video streams already created"); + return nullptr; + } + + InitializeEncodedVideoStreams(script_state); + return encoded_video_streams_; } RTCRtpReceiverPlatform* RTCRtpReceiver::platform_receiver() { @@ -195,6 +219,9 @@ visitor->Trace(transport_); visitor->Trace(streams_); visitor->Trace(transceiver_); + visitor->Trace(video_from_depacketizer_underlying_source_); + visitor->Trace(video_to_decoder_underlying_sink_); + visitor->Trace(encoded_video_streams_); ScriptWrappable::Trace(visitor); } @@ -287,4 +314,74 @@ return parameters; } +void RTCRtpReceiver::RegisterEncodedVideoStreamCallback() { + DCHECK(!platform_receiver() + ->GetEncodedVideoStreamTransformer() + ->HasTransformerCallback()); + platform_receiver() + ->GetEncodedVideoStreamTransformer() + ->SetTransformerCallback(WTF::BindRepeating( + &RTCRtpReceiver::OnFrameFromDepacketizer, WrapWeakPersistent(this))); +} + +void RTCRtpReceiver::UnregisterEncodedVideoStreamCallback() { + DCHECK(!platform_receiver() + ->GetEncodedVideoStreamTransformer() + ->HasTransformerCallback()); + platform_receiver() + ->GetEncodedVideoStreamTransformer() + ->ResetTransformerCallback(); +} + +void RTCRtpReceiver::InitializeEncodedVideoStreams(ScriptState* script_state) { + DCHECK(!encoded_video_streams_); + DCHECK(!video_from_depacketizer_underlying_source_); + DCHECK(!video_to_decoder_underlying_sink_); + DCHECK(force_encoded_video_insertable_streams_); + + encoded_video_streams_ = RTCInsertableStreams::Create(); + + // Set up readable. + video_from_depacketizer_underlying_source_ = + MakeGarbageCollected<RTCEncodedVideoUnderlyingSource>( + script_state, + WTF::Bind(&RTCRtpReceiver::UnregisterEncodedVideoStreamCallback, + WrapWeakPersistent(this))); + // The high water mark for the readable stream is set to 0 so that frames are + // removed from the queue right away, without introducing a new buffer. + encoded_video_streams_->setReadableStream( + ReadableStream::CreateWithCountQueueingStrategy( + script_state, video_from_depacketizer_underlying_source_, + /*high_water_mark=*/0)); + + // Set up writable. + video_to_decoder_underlying_sink_ = + MakeGarbageCollected<RTCEncodedVideoUnderlyingSink>( + script_state, + WTF::BindRepeating( + [](RTCRtpReceiver* receiver) + -> RTCEncodedVideoStreamTransformer* { + return receiver ? receiver->platform_receiver() + ->GetEncodedVideoStreamTransformer() + : nullptr; + }, + WrapWeakPersistent(this))); + // The high water mark for the stream is set to 1 so that the stream seems + // ready to write, but without queuing frames. + encoded_video_streams_->setWritableStream( + WritableStream::CreateWithCountQueueingStrategy( + script_state, video_to_decoder_underlying_sink_, + /*high_water_mark=*/1)); +} + +void RTCRtpReceiver::OnFrameFromDepacketizer( + std::unique_ptr<webrtc::video_coding::EncodedFrame> encoded_video_frame, + std::vector<uint8_t> additional_data, + uint32_t ssrc) { + if (video_from_depacketizer_underlying_source_) { + video_from_depacketizer_underlying_source_->OnFrameFromSource( + std::move(encoded_video_frame), std::move(additional_data)); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h index 8380bc9..82e1c06 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.h
@@ -21,8 +21,16 @@ #include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_receiver_platform.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h" +namespace webrtc { +namespace video_coding { +class EncodedFrame; +} // namespace video_coding +} // namespace webrtc + namespace blink { class RTCDtlsTransport; +class RTCEncodedVideoUnderlyingSource; +class RTCEncodedVideoUnderlyingSink; class RTCInsertableStreams; class RTCPeerConnection; class RTCRtpCapabilities; @@ -37,7 +45,8 @@ RTCRtpReceiver(RTCPeerConnection*, std::unique_ptr<RTCRtpReceiverPlatform>, MediaStreamTrack*, - MediaStreamVector); + MediaStreamVector, + bool force_encoded_video_insertable_streams); static RTCRtpCapabilities* getCapabilities(const String& kind); @@ -65,9 +74,16 @@ void Trace(Visitor*) override; private: - Member<RTCPeerConnection> pc_; void SetContributingSourcesNeedsUpdating(); + void RegisterEncodedVideoStreamCallback(); + void UnregisterEncodedVideoStreamCallback(); + void InitializeEncodedVideoStreams(ScriptState*); + void OnFrameFromDepacketizer( + std::unique_ptr<webrtc::video_coding::EncodedFrame> frame, + std::vector<uint8_t> additional_data, + uint32_t ssrc); + Member<RTCPeerConnection> pc_; std::unique_ptr<RTCRtpReceiverPlatform> receiver_; Member<MediaStreamTrack> track_; Member<RTCDtlsTransport> transport_; @@ -83,6 +99,13 @@ // observed delay may differ depending on the congestion control. |nullopt| // means default value must be used. base::Optional<double> playout_delay_hint_; + + // Insertable Streams support + bool force_encoded_video_insertable_streams_; + Member<RTCEncodedVideoUnderlyingSource> + video_from_depacketizer_underlying_source_; + Member<RTCEncodedVideoUnderlyingSink> video_to_decoder_underlying_sink_; + Member<RTCInsertableStreams> encoded_video_streams_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc index f22e061..e2584ef 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/logging.h" +#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_video_stream_transformer.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_sender_platform.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_stats.h" @@ -135,7 +136,8 @@ public: RTCRtpReceiverInternal( scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection, - RtpReceiverState state) + RtpReceiverState state, + bool force_encoded_video_insertable_streams) : native_peer_connection_(std::move(native_peer_connection)), main_task_runner_(state.main_task_runner()), signaling_task_runner_(state.signaling_task_runner()), @@ -143,6 +145,12 @@ state_(std::move(state)) { DCHECK(native_peer_connection_); DCHECK(state_.is_initialized()); + if (force_encoded_video_insertable_streams) { + transformer_ = + std::make_unique<RTCEncodedVideoStreamTransformer>(main_task_runner_); + webrtc_receiver_->SetDepacketizerToDecoderFrameTransformer( + transformer_->Delegate()); + } } const RtpReceiverState& state() const { @@ -189,6 +197,10 @@ blink::ToAbslOptional(delay_seconds)); } + RTCEncodedVideoStreamTransformer* GetEncodedVideoStreamTransformer() const { + return transformer_.get(); + } + private: friend class WTF::ThreadSafeRefCounted<RTCRtpReceiverInternal, RTCRtpReceiverInternalTraits>; @@ -214,6 +226,7 @@ const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; const scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner_; const scoped_refptr<webrtc::RtpReceiverInterface> webrtc_receiver_; + std::unique_ptr<RTCEncodedVideoStreamTransformer> transformer_; RtpReceiverState state_; }; @@ -240,10 +253,12 @@ RTCRtpReceiverImpl::RTCRtpReceiverImpl( scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection, - RtpReceiverState state) + RtpReceiverState state, + bool force_encoded_video_insertable_streams) : internal_(base::MakeRefCounted<RTCRtpReceiverInternal>( std::move(native_peer_connection), - std::move(state))) {} + std::move(state), + force_encoded_video_insertable_streams)) {} RTCRtpReceiverImpl::RTCRtpReceiverImpl(const RTCRtpReceiverImpl& other) : internal_(other.internal_) {} @@ -316,6 +331,11 @@ internal_->SetJitterBufferMinimumDelay(delay_seconds); } +RTCEncodedVideoStreamTransformer* +RTCRtpReceiverImpl::GetEncodedVideoStreamTransformer() const { + return internal_->GetEncodedVideoStreamTransformer(); +} + RTCRtpReceiverOnlyTransceiver::RTCRtpReceiverOnlyTransceiver( std::unique_ptr<RTCRtpReceiverPlatform> receiver) : receiver_(std::move(receiver)) {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.h b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.h index df2b197..6f9b1c1 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.h
@@ -24,6 +24,8 @@ namespace blink { +class RTCEncodedVideoStreamTransformer; + // This class represents the state of a receiver; a snapshot of what a // webrtc-layer receiver looked like when it was inspected on the signaling // thread such that this information can be moved to the main thread in a single @@ -113,7 +115,8 @@ RTCRtpReceiverImpl( scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection, - RtpReceiverState state); + RtpReceiverState state, + bool force_encoded_video_insertable_streams); RTCRtpReceiverImpl(const RTCRtpReceiverImpl& other); ~RTCRtpReceiverImpl() override; @@ -135,6 +138,8 @@ std::unique_ptr<webrtc::RtpParameters> GetParameters() const override; void SetJitterBufferMinimumDelay( base::Optional<double> delay_seconds) override; + RTCEncodedVideoStreamTransformer* GetEncodedVideoStreamTransformer() + const override; private: class RTCRtpReceiverInternal;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl_test.cc index 169fa78a..10642804 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl_test.cc
@@ -59,7 +59,8 @@ } std::unique_ptr<RTCRtpReceiverImpl> CreateReceiver( - scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track) { + scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track, + bool force_encoded_video_insertable_streams = false) { std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref; base::RunLoop run_loop; @@ -76,8 +77,9 @@ main_thread_, dependency_factory_->GetWebRtcSignalingTaskRunner(), mock_webrtc_receiver_.get(), std::move(track_ref), {}); state.Initialize(); - return std::make_unique<RTCRtpReceiverImpl>(peer_connection_.get(), - std::move(state)); + return std::make_unique<RTCRtpReceiverImpl>( + peer_connection_.get(), std::move(state), + force_encoded_video_insertable_streams); } scoped_refptr<blink::TestWebRTCStatsReportObtainer> GetStats() { @@ -117,6 +119,7 @@ EXPECT_FALSE(receiver_->Track().IsNull()); EXPECT_EQ(receiver_->Track().Id().Utf8(), webrtc_track->id()); EXPECT_EQ(receiver_->state().track_ref()->webrtc_track(), webrtc_track); + EXPECT_FALSE(receiver_->GetEncodedVideoStreamTransformer()); } TEST_F(RTCRtpReceiverImplTest, ShallowCopy) { @@ -165,4 +168,12 @@ EXPECT_EQ(stats->Timestamp(), 1.234); } +TEST_F(RTCRtpReceiverImplTest, CreateReceiverWithInsertableStream) { + scoped_refptr<blink::MockWebRtcAudioTrack> webrtc_track = + blink::MockWebRtcAudioTrack::Create("webrtc_track"); + receiver_ = CreateReceiver(webrtc_track, + /*force_encoded_video_insertable_streams=*/true); + EXPECT_TRUE(receiver_->GetEncodedVideoStreamTransformer()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc index ec2155f..a3bdcfa 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
@@ -16,11 +16,16 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_header_extension_capability.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_header_extension_parameters.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/core/streams/readable_stream.h" +#include "third_party/blink/renderer/core/streams/writable_stream.h" #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h" #include "third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_error_util.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_insertable_streams.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_stats_report.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_void_request_script_promise_resolver_impl.h" @@ -29,6 +34,7 @@ #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_dtmf_sender_handler.h" +#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_video_stream_transformer.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_stats.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_void_request.h" #include "third_party/blink/renderer/platform/wtf/functional.h" @@ -340,15 +346,20 @@ std::unique_ptr<RTCRtpSenderPlatform> sender, String kind, MediaStreamTrack* track, - MediaStreamVector streams) + MediaStreamVector streams, + bool force_encoded_video_insertable_streams) : pc_(pc), sender_(std::move(sender)), kind_(std::move(kind)), track_(track), - streams_(std::move(streams)) { + streams_(std::move(streams)), + force_encoded_video_insertable_streams_( + force_encoded_video_insertable_streams) { DCHECK(pc_); DCHECK(sender_); DCHECK(!track || kind_ == track->kind()); + if (force_encoded_video_insertable_streams_) + RegisterEncodedVideoStreamCallback(); } MediaStreamTrack* RTCRtpSender::track() { @@ -596,9 +607,20 @@ RTCInsertableStreams* RTCRtpSender::createEncodedVideoStreams( ScriptState* script_state, ExceptionState& exception_state) { - exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, - "Not supported"); - return nullptr; + if (!force_encoded_video_insertable_streams_) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "Encoded video streams not requested at PC initialization"); + return nullptr; + } + if (encoded_video_streams_) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "Encoded video streams already created"); + return nullptr; + } + + InitializeEncodedVideoStreams(script_state); + return encoded_video_streams_; } void RTCRtpSender::Trace(Visitor* visitor) { @@ -609,6 +631,9 @@ visitor->Trace(streams_); visitor->Trace(last_returned_parameters_); visitor->Trace(transceiver_); + visitor->Trace(video_from_encoder_underlying_source_); + visitor->Trace(video_to_packetizer_underlying_sink_); + visitor->Trace(encoded_video_streams_); ScriptWrappable::Trace(visitor); } @@ -668,4 +693,67 @@ return capabilities; } +void RTCRtpSender::RegisterEncodedVideoStreamCallback() { + DCHECK(!web_sender() + ->GetEncodedVideoStreamTransformer() + ->HasTransformerCallback()); + web_sender()->GetEncodedVideoStreamTransformer()->SetTransformerCallback( + WTF::BindRepeating(&RTCRtpSender::OnFrameFromEncoder, + WrapWeakPersistent(this))); +} + +void RTCRtpSender::UnregisterEncodedVideoStreamCallback() { + web_sender()->GetEncodedVideoStreamTransformer()->ResetTransformerCallback(); +} + +void RTCRtpSender::InitializeEncodedVideoStreams(ScriptState* script_state) { + DCHECK(!video_from_encoder_underlying_source_); + DCHECK(!video_to_packetizer_underlying_sink_); + DCHECK(!encoded_video_streams_); + DCHECK(force_encoded_video_insertable_streams_); + + encoded_video_streams_ = RTCInsertableStreams::Create(); + + // Set up readable stream. + video_from_encoder_underlying_source_ = + MakeGarbageCollected<RTCEncodedVideoUnderlyingSource>( + script_state, + WTF::Bind(&RTCRtpSender::UnregisterEncodedVideoStreamCallback, + WrapWeakPersistent(this))); + // The high water mark for the readable stream is set to 0 so that frames are + // removed from the queue right away, without introducing any buffering. + encoded_video_streams_->setReadableStream( + ReadableStream::CreateWithCountQueueingStrategy( + script_state, video_from_encoder_underlying_source_, + /*high_water_mark=*/0)); + + // Set up writable stream. + video_to_packetizer_underlying_sink_ = + MakeGarbageCollected<RTCEncodedVideoUnderlyingSink>( + script_state, + WTF::BindRepeating( + [](RTCRtpSender* sender) -> RTCEncodedVideoStreamTransformer* { + return sender ? sender->web_sender() + ->GetEncodedVideoStreamTransformer() + : nullptr; + }, + WrapWeakPersistent(this))); + // The high water mark for the stream is set to 1 so that the stream is + // ready to write, but without queuing frames. + encoded_video_streams_->setWritableStream( + WritableStream::CreateWithCountQueueingStrategy( + script_state, video_to_packetizer_underlying_sink_, + /*high_water_mark=*/1)); +} + +void RTCRtpSender::OnFrameFromEncoder( + std::unique_ptr<webrtc::video_coding::EncodedFrame> frame, + std::vector<uint8_t> additional_data, + uint32_t ssrc) { + if (video_from_encoder_underlying_source_) { + video_from_encoder_underlying_source_->OnFrameFromSource( + std::move(frame), std::move(additional_data)); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h index c9d86b0..16d2bce 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h
@@ -19,16 +19,25 @@ #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/webrtc/api/rtp_transceiver_interface.h" +namespace webrtc { +namespace video_coding { +class EncodedFrame; +} // namespace video_coding +} // namespace webrtc + namespace blink { class ExceptionState; class MediaStreamTrack; class RTCDtlsTransport; class RTCDTMFSender; +class RTCEncodedVideoUnderlyingSink; +class RTCEncodedVideoUnderlyingSource; class RTCInsertableStreams; class RTCPeerConnection; class RTCRtpCapabilities; class RTCRtpTransceiver; +class RTCInsertableStreams; webrtc::RtpEncodingParameters ToRtpEncodingParameters( const RTCRtpEncodingParameters*); @@ -48,7 +57,8 @@ std::unique_ptr<RTCRtpSenderPlatform>, String kind, MediaStreamTrack*, - MediaStreamVector streams); + MediaStreamVector streams, + bool force_encoded_video_insertable_streams); MediaStreamTrack* track(); RTCDtlsTransport* transport(); @@ -79,6 +89,14 @@ void Trace(Visitor*) override; private: + void RegisterEncodedVideoStreamCallback(); + void UnregisterEncodedVideoStreamCallback(); + void InitializeEncodedVideoStreams(ScriptState*); + void OnFrameFromEncoder( + std::unique_ptr<webrtc::video_coding::EncodedFrame> frame, + std::vector<uint8_t> additional_data, + uint32_t ssrc); + Member<RTCPeerConnection> pc_; std::unique_ptr<RTCRtpSenderPlatform> sender_; // The spec says that "kind" should be looked up in transceiver, but keeping @@ -90,6 +108,12 @@ MediaStreamVector streams_; Member<RTCRtpSendParameters> last_returned_parameters_; Member<RTCRtpTransceiver> transceiver_; + + // Insertable Streams support + bool force_encoded_video_insertable_streams_; + Member<RTCEncodedVideoUnderlyingSource> video_from_encoder_underlying_source_; + Member<RTCEncodedVideoUnderlyingSink> video_to_packetizer_underlying_sink_; + Member<RTCInsertableStreams> encoded_video_streams_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc index 7722e11..91599bb 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc
@@ -9,6 +9,7 @@ #include "base/logging.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_dtmf_sender_handler.h" +#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_video_stream_transformer.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_stats.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_void_request.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" @@ -183,7 +184,8 @@ RTCRtpSenderInternal( scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection, scoped_refptr<blink::WebRtcMediaStreamTrackAdapterMap> track_map, - RtpSenderState state) + RtpSenderState state, + bool force_encoded_video_insertable_streams) : native_peer_connection_(std::move(native_peer_connection)), track_map_(std::move(track_map)), main_task_runner_(state.main_task_runner()), @@ -192,6 +194,12 @@ state_(std::move(state)) { DCHECK(track_map_); DCHECK(state_.is_initialized()); + if (force_encoded_video_insertable_streams) { + transformer_ = + std::make_unique<RTCEncodedVideoStreamTransformer>(main_task_runner_); + webrtc_sender_->SetEncoderToPacketizerFrameTransformer( + transformer_->Delegate()); + } } const RtpSenderState& state() const { @@ -307,6 +315,10 @@ WrapRefCounted(this), stream_ids)); } + RTCEncodedVideoStreamTransformer* GetEncodedVideoStreamTransformer() const { + return transformer_.get(); + } + private: friend class WTF::ThreadSafeRefCounted<RTCRtpSenderInternal, RTCRtpSenderInternalTraits>; @@ -393,6 +405,7 @@ const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; const scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner_; const scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender_; + std::unique_ptr<RTCEncodedVideoStreamTransformer> transformer_; RtpSenderState state_; webrtc::RtpParameters parameters_; }; @@ -421,11 +434,13 @@ RTCRtpSenderImpl::RTCRtpSenderImpl( scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection, scoped_refptr<blink::WebRtcMediaStreamTrackAdapterMap> track_map, - RtpSenderState state) + RtpSenderState state, + bool force_encoded_video_insertable_streams) : internal_(base::MakeRefCounted<RTCRtpSenderInternal>( std::move(native_peer_connection), std::move(track_map), - std::move(state))) {} + std::move(state), + force_encoded_video_insertable_streams)) {} RTCRtpSenderImpl::RTCRtpSenderImpl(const RTCRtpSenderImpl& other) : internal_(other.internal_) {} @@ -522,6 +537,11 @@ return internal_->RemoveFromPeerConnection(pc); } +RTCEncodedVideoStreamTransformer* +RTCRtpSenderImpl::GetEncodedVideoStreamTransformer() const { + return internal_->GetEncodedVideoStreamTransformer(); +} + RTCRtpSenderOnlyTransceiver::RTCRtpSenderOnlyTransceiver( std::unique_ptr<blink::RTCRtpSenderPlatform> sender) : sender_(std::move(sender)) {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.h b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.h index cc0aec92..5ba8472a 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.h
@@ -23,6 +23,8 @@ namespace blink { +class RTCEncodedVideoStreamTransformer; + // This class represents the state of a sender; a snapshot of what a // webrtc-layer sender looked like when it was inspected on the signaling thread // such that this information can be moved to the main thread in a single @@ -120,7 +122,8 @@ RTCRtpSenderImpl( scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection, scoped_refptr<blink::WebRtcMediaStreamTrackAdapterMap> track_map, - RtpSenderState state); + RtpSenderState state, + bool force_encoded_video_insertable_streams); RTCRtpSenderImpl(const RTCRtpSenderImpl& other); ~RTCRtpSenderImpl() override; RTCRtpSenderImpl& operator=(const RTCRtpSenderImpl& other); @@ -145,6 +148,8 @@ void GetStats(RTCStatsReportCallback, const Vector<webrtc::NonStandardGroupId>&) override; void SetStreams(const Vector<String>& stream_ids) override; + RTCEncodedVideoStreamTransformer* GetEncodedVideoStreamTransformer() + const override; // The ReplaceTrack() that takes a blink::RTCVoidRequest is implemented on // top of this, which returns the result in a callback instead. Allows doing
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl_test.cc index 8d180e74..f88d0c24 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl_test.cc
@@ -96,7 +96,8 @@ std::vector<std::string>()); sender_state.Initialize(); return std::make_unique<RTCRtpSenderImpl>( - peer_connection_.get(), track_map_, std::move(sender_state)); + peer_connection_.get(), track_map_, std::move(sender_state), + /*force_encoded_video_insertable_streams=*/false); } // Calls replaceTrack(), which is asynchronous, returning a callback that when
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.cc index 250c8df..12b89fa 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.cc
@@ -186,15 +186,18 @@ RTCRtpTransceiverInternal( scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection, scoped_refptr<blink::WebRtcMediaStreamTrackAdapterMap> track_map, - RtpTransceiverState state) + RtpTransceiverState state, + bool force_encoded_video_insertable_streams) : main_task_runner_(state.main_task_runner()), signaling_task_runner_(state.signaling_task_runner()), webrtc_transceiver_(state.webrtc_transceiver()), state_(std::move(state)) { sender_ = std::make_unique<blink::RTCRtpSenderImpl>( - native_peer_connection, track_map, state_.MoveSenderState()); + native_peer_connection, track_map, state_.MoveSenderState(), + force_encoded_video_insertable_streams); receiver_ = std::make_unique<blink::RTCRtpReceiverImpl>( - native_peer_connection, state_.MoveReceiverState()); + native_peer_connection, state_.MoveReceiverState(), + force_encoded_video_insertable_streams); } const RtpTransceiverState& state() const { @@ -297,11 +300,13 @@ RTCRtpTransceiverImpl::RTCRtpTransceiverImpl( scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection, scoped_refptr<blink::WebRtcMediaStreamTrackAdapterMap> track_map, - RtpTransceiverState transceiver_state) + RtpTransceiverState transceiver_state, + bool force_encoded_video_insertable_streams) : internal_(base::MakeRefCounted<RTCRtpTransceiverInternal>( std::move(native_peer_connection), std::move(track_map), - std::move(transceiver_state))) {} + std::move(transceiver_state), + force_encoded_video_insertable_streams)) {} RTCRtpTransceiverImpl::RTCRtpTransceiverImpl(const RTCRtpTransceiverImpl& other) : internal_(other.internal_) {}
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.h b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.h index 7e900aa..804c8ce 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.h
@@ -152,7 +152,8 @@ RTCRtpTransceiverImpl( scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection, scoped_refptr<blink::WebRtcMediaStreamTrackAdapterMap> track_map, - RtpTransceiverState state); + RtpTransceiverState state, + bool force_encoded_video_insertable_streams); RTCRtpTransceiverImpl(const RTCRtpTransceiverImpl& other); ~RTCRtpTransceiverImpl() override;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl_test.cc index 7553443..b22e1971 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl_test.cc
@@ -254,8 +254,9 @@ EXPECT_FALSE(transceiver_state.is_initialized()); transceiver_state.Initialize(); - RTCRtpTransceiverImpl transceiver(peer_connection_.get(), track_map_, - std::move(transceiver_state)); + RTCRtpTransceiverImpl transceiver( + peer_connection_.get(), track_map_, std::move(transceiver_state), + /*force_encoded_video_insertable_streams=*/false); EXPECT_TRUE(transceiver.Mid().IsNull()); EXPECT_TRUE(transceiver.Sender()); EXPECT_TRUE(transceiver.Receiver()); @@ -298,8 +299,9 @@ // Modifying the webrtc transceiver after the initial state was created should // not have affected the transceiver state. - RTCRtpTransceiverImpl transceiver(peer_connection_.get(), track_map_, - std::move(initial_transceiver_state)); + RTCRtpTransceiverImpl transceiver( + peer_connection_.get(), track_map_, std::move(initial_transceiver_state), + /*force_encoded_video_insertable_streams=*/false); EXPECT_TRUE(transceiver.Mid().IsNull()); EXPECT_TRUE(transceiver.Sender()); EXPECT_TRUE(transceiver.Receiver()); @@ -343,7 +345,8 @@ EXPECT_FALSE(transceiver_state.is_initialized()); transceiver_state.Initialize(); transceiver.reset(new RTCRtpTransceiverImpl( - peer_connection_.get(), track_map_, std::move(transceiver_state))); + peer_connection_.get(), track_map_, std::move(transceiver_state), + /*force_encoded_video_insertable_streams=*/false)); } DCHECK(transceiver); EXPECT_FALSE(transceiver->Stopped()); @@ -402,8 +405,9 @@ modified_transceiver_state.Initialize(); // Construct a transceiver from the initial state. - RTCRtpTransceiverImpl transceiver(peer_connection_.get(), track_map_, - std::move(initial_transceiver_state)); + RTCRtpTransceiverImpl transceiver( + peer_connection_.get(), track_map_, std::move(initial_transceiver_state), + /*force_encoded_video_insertable_streams=*/false); // Setting the state with TransceiverStateUpdateMode::kSetDescription should // make the transceiver state up-to-date, except leaving // "transceiver.direction" and "transceiver.sender.track" unmodified.
diff --git a/third_party/blink/renderer/platform/mojo/blink_typemaps.gni b/third_party/blink/renderer/platform/mojo/blink_typemaps.gni index 7fad5d7..434a7cb 100644 --- a/third_party/blink/renderer/platform/mojo/blink_typemaps.gni +++ b/third_party/blink/renderer/platform/mojo/blink_typemaps.gni
@@ -3,7 +3,7 @@ # found in the LICENSE file. typemaps = [ - "//media/capture/mojom/video_capture_types.typemap", + "//media/capture/mojom/video_capture_types_for_blink.typemap", "//media/mojo/mojom/audio_parameters.typemap", "//services/network/public/cpp/http_request_headers.typemap", "//services/network/public/cpp/ip_address.typemap",
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_rtp_receiver_platform.h b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_receiver_platform.h index f753e6a..40042a71 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_rtp_receiver_platform.h +++ b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_receiver_platform.h
@@ -20,6 +20,7 @@ class RTCRtpSource; class WebMediaStreamTrack; +class RTCEncodedVideoStreamTransformer; // Implementations of this interface keep the corresponding WebRTC-layer // receiver alive through reference counting. Multiple |RTCRtpReceiverPlatform|s @@ -46,6 +47,10 @@ virtual std::unique_ptr<webrtc::RtpParameters> GetParameters() const = 0; virtual void SetJitterBufferMinimumDelay( base::Optional<double> delay_seconds) = 0; + virtual RTCEncodedVideoStreamTransformer* GetEncodedVideoStreamTransformer() + const { + return nullptr; + } }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_rtp_sender_platform.h b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_sender_platform.h index b9abe44..d474552 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_rtp_sender_platform.h +++ b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_sender_platform.h
@@ -20,6 +20,7 @@ class RTCVoidRequest; class WebMediaStreamTrack; class RtcDtmfSenderHandler; +class RTCEncodedVideoStreamTransformer; // Implementations of this interface keep the corresponding WebRTC-layer sender // alive through reference counting. Multiple |RTCRtpSenderPlatform|s could @@ -53,6 +54,10 @@ virtual void GetStats(RTCStatsReportCallback, const Vector<webrtc::NonStandardGroupId>&) = 0; virtual void SetStreams(const Vector<String>& stream_ids) = 0; + virtual RTCEncodedVideoStreamTransformer* GetEncodedVideoStreamTransformer() + const { + return nullptr; + } }; } // namespace blink
diff --git a/third_party/blink/tools/blinkpy/third_party/README.chromium b/third_party/blink/tools/blinkpy/third_party/README.chromium index 22beedb..4ae445d 100644 --- a/third_party/blink/tools/blinkpy/third_party/README.chromium +++ b/third_party/blink/tools/blinkpy/third_party/README.chromium
@@ -43,6 +43,7 @@ for more details on maintenance. Local Modifications: - Removed all files except for those listed in wpt/WPTWhiteList. -- Removed a few unimported subcommands from tools/wpt/path. - Cherry-picked the server part of https://github.com/web-platform-tests/wpt/pull/21705 (we cannot yet directly roll to that revision because of MANIFEST v8 changes). +- Cherry-picked the server part of https://github.com/web-platform-tests/wpt/pull/21845 + (Same reason with the previous cherry-pick. This enables pywebsocket3 usage).
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/WPTWhiteList b/third_party/blink/tools/blinkpy/third_party/wpt/WPTWhiteList index 34e0c68..22b82bf 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/WPTWhiteList +++ b/third_party/blink/tools/blinkpy/third_party/wpt/WPTWhiteList
@@ -5,6 +5,7 @@ ./tools/__init__.py ./tools/ci/commands.json ./tools/conftest.py +./tools/docker/commands.json ./tools/gitignore/__init__.py ./tools/gitignore/gitignore.py ./tools/lint/__init__.py
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh index 34b2a1c1..e043ecb 100755 --- a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh +++ b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
@@ -21,9 +21,8 @@ echo "WPTHead: " `git rev-parse HEAD` # Apply local changes. - git apply $DIR/chromium.patch - # Chromium presubmit requires scripts with shebang to be executable. - chmod 755 tools/manifest/update.py + git cherry-pick 644a206e8ace488eac7e2b2a58a4b5354b02363a + git cherry-pick 7e52ecb9b61b73425093d39dbadceb9c6e10b754 } function reduce {
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/chromium.patch b/third_party/blink/tools/blinkpy/third_party/wpt/chromium.patch deleted file mode 100644 index e338114b..0000000 --- a/third_party/blink/tools/blinkpy/third_party/wpt/chromium.patch +++ /dev/null
@@ -1,46 +0,0 @@ -diff --git a/tools/wpt/paths b/tools/wpt/paths -index 4528222fbf..93c97dc02b 100644 ---- a/tools/wpt/paths -+++ b/tools/wpt/paths -@@ -1,5 +1,3 @@ --tools/ci/ --tools/docker/ - tools/lint/ - tools/manifest/ - tools/serve/ - tools/wpt/ -diff --git a/tools/serve/serve.py b/tools/serve/serve.py -index 0985810cc5..055b60f1e7 100644 ---- a/tools/serve/serve.py -+++ b/tools/serve/serve.py -@@ -366,6 +366,7 @@ class RoutesBuilder(object): - ("GET", "*.any.serviceworker.html", ServiceWorkersHandler), - ("GET", "*.any.worker.js", AnyWorkerHandler), - ("GET", "*.asis", handlers.AsIsHandler), -+ ("GET", "/.well-known/origin-policy", handlers.PythonScriptHandler), - ("*", "*.py", handlers.PythonScriptHandler), - ("GET", "*", handlers.FileHandler) - ] -@@ -742,6 +743,9 @@ def build_config(override_path=None, **kwargs): - def _make_subdomains_product(s, depth=2): - return {u".".join(x) for x in chain(*(product(s, repeat=i) for i in range(1, depth+1)))} - -+def _make_origin_policy_subdomains(limit): -+ return {u"op%d" % x for x in range(1,limit+1)} -+ - - _subdomains = {u"www", - u"www1", -@@ -753,6 +757,12 @@ _not_subdomains = {u"nonexistent"} - - _subdomains = _make_subdomains_product(_subdomains) - -+# Origin policy subdomains need to not be reused by any other tests, since origin policies have -+# origin-wide impacts like installing a CSP or Feature Policy that could interfere with features -+# under test. -+# See https://github.com/web-platform-tests/rfcs/pull/44. -+_subdomains |= _make_origin_policy_subdomains(99) -+ - _not_subdomains = _make_subdomains_product(_not_subdomains) - -
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/docker/commands.json b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/docker/commands.json new file mode 100644 index 0000000..15182cc --- /dev/null +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/docker/commands.json
@@ -0,0 +1,6 @@ +{ + "docker-run": {"path": "frontend.py", "script": "run", "parser": "parser_run", "help": "Run wpt docker image", + "virtualenv": false}, + "docker-build": {"path": "frontend.py", "script": "build", "help": "Build wpt docker image", + "virtualenv": false} +}
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/localpaths.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/localpaths.py index f6e24b4..ce3b41e3 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/localpaths.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/localpaths.py
@@ -6,7 +6,7 @@ sys.path.insert(0, os.path.join(here)) sys.path.insert(0, os.path.join(here, "wptserve")) -sys.path.insert(0, os.path.join(here, "pywebsocket")) +sys.path.insert(0, os.path.join(here, "third_party", "pywebsocket3")) sys.path.insert(0, os.path.join(here, "third_party", "atomicwrites")) sys.path.insert(0, os.path.join(here, "third_party", "attrs", "src")) sys.path.insert(0, os.path.join(here, "third_party", "funcsigs"))
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py index e1d60962..5317be01 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
@@ -592,21 +592,9 @@ "-w", handlers_root] if ssl_config is not None: - # This is usually done through pywebsocket.main, however we're - # working around that to get the server instance and manually - # setup the wss server. - if pywebsocket._import_ssl(): - tls_module = pywebsocket._TLS_BY_STANDARD_MODULE - elif pywebsocket._import_pyopenssl(): - tls_module = pywebsocket._TLS_BY_PYOPENSSL - else: - print("No SSL module available") - sys.exit(1) - cmd_args += ["--tls", "--private-key", ssl_config["key_path"], - "--certificate", ssl_config["cert_path"], - "--tls-module", tls_module] + "--certificate", ssl_config["cert_path"]] if (bind_address): cmd_args = ["-H", host] + cmd_args
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/paths b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/paths index 93c97dc..35867c4 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/paths +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/paths
@@ -1,3 +1,5 @@ +tools/ci/ +tools/docker/ tools/lint/ tools/manifest/ tools/serve/
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py index e11cae1..7766565 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py
@@ -69,6 +69,31 @@ def as_dict(self): return json_types(self.__dict__) + # Environment variables are limited in size so we need to prune the most egregious contributors + # to size, the origin policy subdomains. + def as_dict_for_wd_env_variable(self): + result = self.as_dict() + + for key in [ + ("subdomains",), + ("domains", "alt"), + ("domains", ""), + ("all_domains", "alt"), + ("all_domains", ""), + ("domains_set",), + ("all_domains_set",) + ]: + target = result + for part in key[:-1]: + target = target[part] + value = target[key[-1]] + if isinstance(value, dict): + target[key[-1]] = {k:v for (k,v) in iteritems(value) if not k.startswith("op")} + else: + target[key[-1]] = [x for x in value if not x.startswith("op")] + + return result + def json_types(obj): if isinstance(obj, dict):
diff --git a/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py b/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py index 8680b260..01261e4 100644 --- a/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py +++ b/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py
@@ -36,7 +36,7 @@ self._config_file = fs.join(self._runtime_path, 'wpt.config.json') finder = PathFinder(fs) - path_to_pywebsocket = finder.path_from_chromium_base('third_party', 'pywebsocket', 'src') + path_to_pywebsocket = finder.path_from_chromium_base('third_party', 'pywebsocket3', 'src') self.path_to_wpt_support = finder.path_from_blink_tools('blinkpy', 'third_party', 'wpt') path_to_wpt_root = fs.join(self.path_to_wpt_support, 'wpt') path_to_wpt_tests = fs.abspath(fs.join(self._port_obj.web_tests_dir(), 'external', 'wpt'))
diff --git a/third_party/blink/tools/blinkpy/web_tests/servers/wptserve_unittest.py b/third_party/blink/tools/blinkpy/web_tests/servers/wptserve_unittest.py index b996f07..59680b1f 100644 --- a/third_party/blink/tools/blinkpy/web_tests/servers/wptserve_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/servers/wptserve_unittest.py
@@ -59,7 +59,7 @@ self.assertEqual(server._env, { 'MOCK_ENVIRON_COPY': '1', 'PATH': '/bin:/mock/bin', - 'PYTHONPATH': '/mock-checkout/third_party/pywebsocket/src' + 'PYTHONPATH': '/mock-checkout/third_party/pywebsocket3/src' }) def test_prepare_config(self):
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations index 6fd92b7..fc4dbb01 100644 --- a/third_party/blink/web_tests/MSANExpectations +++ b/third_party/blink/web_tests/MSANExpectations
@@ -119,7 +119,7 @@ crbug.com/856601 [ Linux ] external/wpt/IndexedDB/interfaces.any.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/appmanifest/idlharness.window.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/bluetooth/idl/idlharness.tentative.window.html [ Pass Timeout ] -crbug.com/856601 [ Linux ] virtual/web-bluetooth-new-permissions-backend/external/wpt/bluetooth/idlharness.tentative.https.window.html [ Pass Timeout ] +crbug.com/856601 [ Linux ] virtual/web-bluetooth-new-permissions-backend/external/wpt/bluetooth/idl/idlharness.tentative.https.window.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/cookie-store/idlharness.tentative.https.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/css/css-animations/idlharness.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/css/css-font-loading/idlharness.https.html [ Pass Timeout ] @@ -190,6 +190,7 @@ crbug.com/856601 [ Linux ] external/wpt/wake-lock/idlharness.https.any.worker.html [ Pass Timeout ] crbug.com/856601 [ Linux ] virtual/omt-worker-fetch/external/wpt/fetch/api/idl.any.sharedworker.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/trusted-types/idlharness.tentative.window.html [ Pass Timeout ] +crbug.com/856601 [ Linux ] external/wpt/trusted-types/idlharness.tentative.https.window.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/hr-time/idlharness.any.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/media-playback-quality/idlharness.window.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/native-file-system/idlharness.https.any.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index e606975..4697c7f 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1120,9 +1120,9 @@ crbug.com/988015 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-dynamic-add-003.html [ Failure ] crbug.com/994172 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-dynamic-add-007.html [ Pass Crash ] crbug.com/924142 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-dynamic-add-010.html [ Crash Pass ] -crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-001.html [ Failure ] -crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html [ Failure ] -crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-003.html [ Failure ] +crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-001.html [ Crash Failure ] +crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html [ Crash Failure ] +crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-003.html [ Crash Failure ] crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-list-item-001.html [ Failure ] crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-margin-001.xht [ Failure ] crbug.com/591099 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-margin-002.xht [ Failure ] @@ -1204,6 +1204,7 @@ crbug.com/874506 virtual/layout_ng_block_frag/fast/multicol/event-offset-complex-tree.html [ Failure ] crbug.com/874506 virtual/layout_ng_block_frag/fast/multicol/event-offset.html [ Failure ] crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/event-offset-in-nested.html [ Failure ] +crbug.com/875235 virtual/layout_ng_block_frag/fast/multicol/fieldset-as-multicol.html [ Crash Failure ] crbug.com/874506 virtual/layout_ng_block_frag/fast/multicol/filter-in-second-column.html [ Failure ] crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/fixedpos-child-becomes-static.html [ Failure ] crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/float-after-break-after.html [ Failure ] @@ -1606,6 +1607,13 @@ # Fieldset in NG # +crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/css/css-contain/contain-size-breaks-001.html [ Crash Failure ] +crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/css/css-contain/contain-size-monolithic-001.html [ Crash Failure ] +crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/css/css-contain/contain-size-multicol-001.html [ Failure ] +crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-multicol-001.html [ Failure ] +crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-multicol-002.html [ Crash Failure ] +crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-multicol-003.html [ Failure ] +crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-multicol.html [ Crash Failure ] crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-overflow.html [ Failure ] crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-overflow-hidden.html [ Failure ] crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-painting-order.html [ Failure ] @@ -2389,6 +2397,9 @@ crbug.com/1032016 http/tests/devtools/bindings/inline-styles-binding.js [ Pass Failure ] crbug.com/1032016 http/tests/devtools/bindings/livelocation-main-frame-navigated.js [ Pass Failure ] +# Temporarily disabled so we can land a frontend change that removes side-effect handling in the frontend. +crbug.com/1031243 http/tests/devtools/console-cd-completions.js [ Pass Failure ] + # We only want to run one of the web-animations-api tests in stable mode. crbug.com/441553 virtual/stable/web-animations-api/* [ Skip ] # These tests *only* run in stable, to verify that these features are unsupported and throw exceptions. @@ -6583,7 +6594,7 @@ crbug.com/1048149 [ Mac ] virtual/controls-refresh/color/color-picker-zoom150-bottom-edge-no-nan.html [ Pass Crash ] # This used to be [ Pass Crash ], but as of crbug.com/1050039 it started flaking as well. crbug.com/1048149 crbug.com/1050121 [ Mac ] virtual/controls-refresh/month-picker/month-picker-appearance-zoom150.html [ Pass Failure Crash Failure ] -crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/calendar-picker-key-operations.html [ Pass Crash ] +crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/calendar-picker-key-operations.html [ Pass Crash Timeout ] crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/calendar-picker-touch-operations.html [ Pass Crash ] crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/calendar-picker-type-change-onchange.html [ Pass Crash ] crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/date-picker-choose-default-value-after-set-value.html [ Pass Crash ] @@ -6592,7 +6603,7 @@ crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/month-picker-appearance-step.html [ Pass Crash ] crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/month-picker-appearance.html [ Pass Crash ] crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/month-picker-choose-default-value-after-set-value.html [ Pass Crash ] -crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/month-picker-key-operations.html [ Pass Crash ] +crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/month-picker-key-operations.html [ Pass Crash Timeout ] crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/month-picker-mouse-operations.html [ Pass Crash ] crbug.com/1048149 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/month-picker-touch-operations.html [ Pass Crash ] @@ -6618,7 +6629,7 @@ crbug.com/1050039 [ Mac ] fast/forms/calendar-picker/calendar-picker-type-change-onchange.html [ Pass Failure ] crbug.com/1050039 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/calendar-picker-appearance.html [ Pass Failure ] crbug.com/1050039 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/datetimelocal-picker-choose-default-value-after-set-value.html [ Pass Failure ] -crbug.com/1050039 [ Mac ] virtual/not-site-per-process/http/tests/devtools/oopif/oopif-storage.js [ Pass Failure ] +crbug.com/1050039 [ Mac ] virtual/not-site-per-process/http/tests/devtools/oopif/oopif-storage.js [ Pass Failure Timeout ] crbug.com/1050039 [ Mac ] virtual/omt-worker-fetch/fast/workers/worker-onerror-01.html [ Pass Failure ] crbug.com/1050039 [ Mac ] virtual/omt-worker-fetch/fast/workers/worker-onerror-02.html [ Pass Failure ] crbug.com/1050039 [ Mac ] virtual/omt-worker-fetch/fast/workers/worker-onerror-03.html [ Pass Failure ] @@ -7021,3 +7032,18 @@ # Temporarily disable to land https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2090785 crbug.com/1011811 third_party/blink/web_tests/http/tests/devtools/changes/changes-sidebar.js [ Pass Failure ] crbug.com/1011811 third_party/blink/web_tests/http/tests/devtools/search/search-in-static.js [ Pass Failure ] + +# Sheriff 2020-03-12 +crbug.com/1060175 [ Mac ] css3/calc/simple-calcs-prefixed.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] css3/calc/simple-calcs.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] editing/selection/programmatic-selection-on-mac-is-directionless.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] fast/events/platform-wheelevent-paging-x-in-scrolling-div.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] fast/events/platform-wheelevent-paging-y-in-scrolling-div.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] http/tests/websocket/multiple-connections-throttled.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] virtual/controls-refresh/datetimelocal-picker/datetimelocal-month-switcher-buttons-invalid.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/calendar-picker/week-picker-key-operations.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-ax-value-changed-notification.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] virtual/form-controls-refresh-disabled/fast/forms/form-control-with-state-eager-tracing-crashTest.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] virtual/threaded/printing/page-count-with-one-word.html [ Pass Timeout ] +crbug.com/1060175 [ Mac ] virtual/web-components-v0-disabled/fast/dom/SelectorAPI/resig-SelectorsAPI-test.xhtml [ Pass Timeout ] +crbug.com/1060175 [ Mac ] virtual/web-components-v0-disabled/fast/dom/zoom-scroll-page-test.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 7ce5e31..3f1380a 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -194,7 +194,7 @@ "fast/multicol", "fragmentation", "printing"], - "args": ["--enable-blink-features=LayoutNGBlockFragmentation"] + "args": ["--enable-blink-features=LayoutNGBlockFragmentation,LayoutNGFieldset"] }, { "prefix": "layout_ng_fragment_traversal", @@ -216,7 +216,7 @@ "external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain", "external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements", "fast/forms/fieldset"], - "args": ["--enable-blink-features=LayoutNGFieldset"] + "args": ["--enable-blink-features=LayoutNGFieldset,LayoutNGBlockFragmentation"] }, { "prefix": "dark-mode-grayscale-images",
diff --git a/third_party/blink/web_tests/editing/caret/selection-with-caret-type-progress-expected.txt b/third_party/blink/web_tests/editing/caret/selection-with-caret-type-progress-expected.txt index 616ec4c..781dff9 100644 --- a/third_party/blink/web_tests/editing/caret/selection-with-caret-type-progress-expected.txt +++ b/third_party/blink/web_tests/editing/caret/selection-with-caret-type-progress-expected.txt
@@ -3,7 +3,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". Try selecting this text by dragging the cursor. Progress cursor should be displayed while doing so. -PASS currentCursorType is "Progress" +PASS cursorInfo is "type=Progress" PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/blink/web_tests/editing/caret/selection-with-caret-type-progress.html b/third_party/blink/web_tests/editing/caret/selection-with-caret-type-progress.html index 3ed3e85..0c8f7b6b 100644 --- a/third_party/blink/web_tests/editing/caret/selection-with-caret-type-progress.html +++ b/third_party/blink/web_tests/editing/caret/selection-with-caret-type-progress.html
@@ -28,8 +28,7 @@ leapForwardAndMove(div.offsetWidth - 10); var cursorInfo = internals.getCurrentCursorInfo(); - var currentCursorType = cursorInfo.substring(cursorInfo.indexOf('=') + 1, cursorInfo.lastIndexOf(' ')); - shouldBeEqualToString('currentCursorType', 'Progress'); + shouldBeEqualToString('cursorInfo', 'type=Progress'); } </script> </body>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json index e8f0a28..71d9503 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
@@ -162295,6 +162295,12 @@ "fetch/api/cors/cors-preflight-redirect.any.worker-expected.txt": [ [] ], + "fetch/api/cors/cors-preflight-response-validation.any-expected.txt": [ + [] + ], + "fetch/api/cors/cors-preflight-response-validation.any.worker-expected.txt": [ + [] + ], "fetch/api/cors/resources/corspreflight.js": [ [] ], @@ -164893,9 +164899,6 @@ "html/cross-origin-embedder-policy/sandbox.https.html.headers": [ [] ], - "html/cross-origin-embedder-policy/service-worker-cache-storage.https-expected.txt": [ - [] - ], "html/cross-origin-embedder-policy/srcdoc.https.html.headers": [ [] ], @@ -172831,6 +172834,12 @@ "mathml/presentation-markup/fractions/frac-numalign-denomalign-001-ref.html": [ [] ], + "mathml/presentation-markup/fractions/frac-parameters-1-expected.txt": [ + [] + ], + "mathml/presentation-markup/fractions/frac-parameters-2-expected.txt": [ + [] + ], "mathml/presentation-markup/fractions/frac-parameters-gap-001-ref.html": [ [] ], @@ -236336,6 +236345,12 @@ {} ] ], + "css/css-values/viewport-units-after-font-load.html": [ + [ + "css/css-values/viewport-units-after-font-load.html", + {} + ] + ], "css/css-values/viewport-units-css2-001.html": [ [ "css/css-values/viewport-units-css2-001.html", @@ -256956,6 +256971,46 @@ } ] ], + "fetch/api/cors/cors-preflight-response-validation.any.js": [ + [ + "fetch/api/cors/cors-preflight-response-validation.any.html", + { + "script_metadata": [ + [ + "script", + "/common/utils.js" + ], + [ + "script", + "../resources/utils.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ] + ] + } + ], + [ + "fetch/api/cors/cors-preflight-response-validation.any.worker.html", + { + "script_metadata": [ + [ + "script", + "/common/utils.js" + ], + [ + "script", + "../resources/utils.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ] + ] + } + ] + ], "fetch/api/cors/cors-preflight-star.any.js": [ [ "fetch/api/cors/cors-preflight-star.any.html", @@ -469463,6 +469518,10 @@ "055f3d1fd2d716a68d857738493815c8772bef06", "reftest" ], + "css/css-values/viewport-units-after-font-load.html": [ + "82e8b73d28dfc57ad572936fe46315d0d0289606", + "testharness" + ], "css/css-values/viewport-units-css2-001.html": [ "c51237dd8a07546d31eef6f6f9b3c84b6ac2b65b", "testharness" @@ -494775,6 +494834,18 @@ "6d69b328644a8aa2155b25a153b094fec2bf18de", "testharness" ], + "fetch/api/cors/cors-preflight-response-validation.any-expected.txt": [ + "17c93ce80ed0f0342c2109c6adab5d5689f481ff", + "support" + ], + "fetch/api/cors/cors-preflight-response-validation.any.js": [ + "718e351c1d3f09aa41cc2ea7f7b071f4a7c48b2a", + "testharness" + ], + "fetch/api/cors/cors-preflight-response-validation.any.worker-expected.txt": [ + "17c93ce80ed0f0342c2109c6adab5d5689f481ff", + "support" + ], "fetch/api/cors/cors-preflight-star.any.js": [ "d76e9a21fd4b946803d8df193fcf00f53921aa9d", "testharness" @@ -501056,7 +501127,7 @@ "support" ], "html/cross-origin-embedder-policy/reporting.https.html": [ - "bb0a6a2b0a8101665a25f2187c138ab0bdfd14e5", + "d883ceb939dd4748ab2338cb636e692203882c18", "testharness" ], "html/cross-origin-embedder-policy/reporting.https.html.sub.headers": [ @@ -501219,10 +501290,6 @@ "6604450991a122e3e241e40b1b9e0516c525389d", "support" ], - "html/cross-origin-embedder-policy/service-worker-cache-storage.https-expected.txt": [ - "10fe5417406e442745bda425931882c39c2e3e41", - "support" - ], "html/cross-origin-embedder-policy/service-worker-cache-storage.https.html": [ "873f06ce4ffbf83bca2ac4dbdc04e5b5bf92abb6", "testharness" @@ -522923,10 +522990,18 @@ "bc9a2f9084471632a88e2b4d56db4557bfbe216e", "reftest" ], + "mathml/presentation-markup/fractions/frac-parameters-1-expected.txt": [ + "eccd329c085bcd27189413782242561f0c3c3a55", + "support" + ], "mathml/presentation-markup/fractions/frac-parameters-1.html": [ "b7efbc78ca01a3919b83edfed67c2721025d4e69", "testharness" ], + "mathml/presentation-markup/fractions/frac-parameters-2-expected.txt": [ + "eb6b9a93c8e1d0a163181908fc25db2c43db7732", + "support" + ], "mathml/presentation-markup/fractions/frac-parameters-2.html": [ "368fc0676d2135b6cd5381a822dd9ec92bf71512", "testharness" @@ -585012,7 +585087,7 @@ "support" ], "tools/requirements_mypy.txt": [ - "a478015893d71a45953f9651844a35c2a46ba7d2", + "988ffe848174f7215278c2c4019f924bed3a61f5", "support" ], "tools/runner/css/bootstrap-theme.min.css": [ @@ -589296,7 +589371,7 @@ "support" ], "tools/wptrunner/requirements_firefox.txt": [ - "ae72940810432bed693c001d4b057a1214fd2dac", + "d541a49f3c0992c4a456ce4ebb717908683a464e", "support" ], "tools/wptrunner/requirements_ie.txt": [ @@ -599784,7 +599859,7 @@ "support" ], "webrtc/protocol/bundle.https.html": [ - "fcc9d470b9f7c5c4215da09666e471dfa0a192d1", + "61d1ff8ac108297dafe333694ddd1194ff53fe26", "testharness" ], "webrtc/protocol/candidate-exchange.https.html": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/viewport-units-after-font-load.html b/third_party/blink/web_tests/external/wpt/css/css-values/viewport-units-after-font-load.html new file mode 100644 index 0000000..82e8b73d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/viewport-units-after-font-load.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values: Viewport units are computed correctly after font load.</title> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel="author" title="Mozilla" href="https://mozilla.org"> +<link rel="help" href="https://drafts.csswg.org/css-values-4/#viewport-relative-lengths"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1620359"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<iframe width=300 height=300 scrolling=no srcdoc=""></iframe> +<script> +let t = async_test("Viewport units are correctly updated after resize even if a font load has happened before"); +let iframe = document.querySelector("iframe"); +onload = t.step_func(function() { + let doc = iframe.contentDocument; + let win = iframe.contentWindow; + doc.body.innerHTML = ` + <div style="width: 100vw; height: 100vh; background: green"></div> + `; + let div = doc.querySelector("div"); + let oldWidth = win.getComputedStyle(div).width; + let oldHeight = win.getComputedStyle(div).height; + assert_equals(oldWidth, win.innerWidth + "px", "Should fill the viewport"); + assert_equals(oldHeight, win.innerHeight + "px", "Should fill the viewport"); + let link = doc.createElement("link"); + link.rel = "stylesheet"; + link.href = "/fonts/ahem.css"; + link.onload = t.step_func(function() { + iframe.width = 400; + win.requestAnimationFrame(t.step_func(function() { + win.requestAnimationFrame(t.step_func_done(function() { + let newWidth = win.getComputedStyle(div).width; + let newHeight = win.getComputedStyle(div).height; + assert_equals(newWidth, win.innerWidth + "px", "Should fill the viewport"); + assert_equals(newHeight, win.innerHeight + "px", "Should fill the viewport"); + assert_equals(newHeight, oldHeight, "Height shouldn't have changed"); + assert_not_equals(newWidth, oldWidth, "Width should have changed"); + })); + })); + }); + doc.body.appendChild(link); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-response-validation.any-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-response-validation.any-expected.txt new file mode 100644 index 0000000..17c93ce8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-response-validation.any-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Preflight response with a bad Access-Control-Allow-Headers assert_unreached: Should have rejected: undefined Reached unreachable code +FAIL Preflight response with a bad Access-Control-Allow-Methods assert_unreached: Should have rejected: undefined Reached unreachable code +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-response-validation.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-response-validation.any.js new file mode 100644 index 0000000..718e351 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-response-validation.any.js
@@ -0,0 +1,33 @@ +// META: script=/common/utils.js +// META: script=../resources/utils.js +// META: script=/common/get-host-info.sub.js + +function corsPreflightResponseValidation(desc, corsUrl, allowHeaders, allowMethods) { + var uuid_token = token(); + var url = corsUrl; + var requestInit = {"mode": "cors"}; + /* Force preflight */ + requestInit["headers"] = {"x-force-preflight": ""}; + + var urlParameters = "?token=" + uuid_token + "&max_age=0"; + urlParameters += "&allow_headers=x-force-preflight"; + if (allowHeaders) + urlParameters += "," + allowHeaders; + if (allowMethods) + urlParameters += "&allow_methods="+ allowMethods; + + promise_test(function(test) { + return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(async function(resp) { + assert_equals(resp.status, 200, "Clean stash response's status is 200"); + await promise_rejects_js(test, TypeError, fetch(url + urlParameters, requestInit)); + + return fetch(url + urlParameters).then(function(resp) { + assert_equals(resp.headers.get("x-did-preflight"), "1", "Preflight request has been made"); + }); + }); + }, desc); +} + +var corsUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; +corsPreflightResponseValidation("Preflight response with a bad Access-Control-Allow-Headers", corsUrl, "Bad value", null); +corsPreflightResponseValidation("Preflight response with a bad Access-Control-Allow-Methods", corsUrl, null, "Bad value");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-response-validation.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-response-validation.any.worker-expected.txt new file mode 100644 index 0000000..17c93ce8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fetch/api/cors/cors-preflight-response-validation.any.worker-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Preflight response with a bad Access-Control-Allow-Headers assert_unreached: Should have rejected: undefined Reached unreachable code +FAIL Preflight response with a bad Access-Control-Allow-Methods assert_unreached: Should have rejected: undefined Reached unreachable code +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting.https.html index bb0a6a2..d883ceb 100644 --- a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting.https.html +++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting.https.html
@@ -28,8 +28,8 @@ } } -let reports = [] -let reportsForReportOnly = [] +const reports = []; +const reportsForReportOnly = []; pollReports('endpoint', reports); pollReports('report-only-endpoint', reportsForReportOnly); @@ -48,6 +48,21 @@ assert_unreached(`A report whose blocked-url is ${blockedUrl} and url is ${contextUrl} is not found.`); } +function checkNavigationReportExistence(reports, blockedUrl, contextUrl) { + blockedUrl = new URL(blockedUrl, location).href; + contextUrl = new URL(contextUrl, location).href; + for (const report of reports) { + if (report.type !== 'coep' || report.url !== contextUrl || + report.body.type !== 'navigation') { + continue; + } + if (report.body['blocked-url'] === blockedUrl) { + return; + } + } + assert_unreached(`A report whose blocked-url is ${blockedUrl} and url is ${contextUrl} is not found.`); +} + function checkReportNonExistence(reports, blockedUrl, contextUrl) { blockedUrl = new URL(blockedUrl, location).href; contextUrl = new URL(contextUrl, location).href; @@ -87,7 +102,8 @@ fetchInIframe(blockedDueToCoep); fetchInIframe(redirect); - await new Promise(resolve => t.step_timeout(resolve, 3000)); + // Wait 3 seconds for reports to settle. + await wait(3000); checkReportNonExistence(reports, sameOriginUrl, iframe.src); checkReportNonExistence(reports, blockedByPureCorp, iframe.src); @@ -121,16 +137,18 @@ } const suffix = 'navigation-corp'; - const sameOrigin = `/common/blank.html?${suffix}`; - const blockedDueToCoep = `${REMOTE_ORIGIN}/common/blank.html?abc&${suffix}`; - const dest = `${REMOTE_ORIGIN}/common/blank.html?xyz&${suffix}`; + const coep = `pipe=header(cross-origin-embedder-policy,require-corp)`; + const sameOrigin = `/common/blank.html?${coep}&${suffix}`; + const blockedDueToCoep = `${REMOTE_ORIGIN}/common/blank.html?${coep}&${suffix}-a`; + const dest = `${REMOTE_ORIGIN}/common/blank.html?${coep}&${suffix}-b`; const redirect = `/common/redirect.py?location=${encodeURIComponent(dest)}&${suffix}`; attachFrame(sameOrigin); attachFrame(blockedDueToCoep); attachFrame(redirect); - await new Promise(resolve => t.step_timeout(resolve, 3000)); + // Wait 3 seconds for reports to settle. + await wait(3000); checkReportNonExistence(reports, sameOrigin, iframe.src); checkCorpReportExistence(reports, blockedDueToCoep, iframe.src); @@ -143,4 +161,98 @@ } }, 'navigation CORP'); -</script> +async_test(async (t) => { + try { + const iframe = document.createElement('iframe'); + t.add_cleanup(() => iframe.remove()); + + const suffix = '&navigation-coep'; + const corp = 'header(cross-origin-resource-policy,cross-origin)'; + const noCoep = `pipe=${corp}`; + const coep = + `pipe=header(cross-origin-embedder-policy,require-corp%3breport-to=%22endpoint%22)|${corp}`; + const coepReportOnly = + `pipe=header(cross-origin-embedder-policy-report-only,require-corp%3breport-to=%22report-only-endpoint%22)|${corp}`; + const path = `/common/blank.html`; + const pipes = [noCoep, coep, coepReportOnly]; + const settings = new Map(); + settings.set(noCoep, { + pipe: noCoep, + value: 'unsafe-none', + reportOnlyValue: 'unsafe-none', + }); + settings.set(coep, { + pipe: coep, + value: 'require-corp', + reportOnlyValue: 'unsafe-none', + }); + settings.set(coepReportOnly, { + pipe: coepReportOnly, + value: 'unsafe-none', + reportOnlyValue: 'require-corp', + }); + + function genUrl(pipe) { + return `${path}?${pipe}${suffix}`; + } + + for (const outer of settings.keys()) { + for (const inner of settings.keys()) { + const iframe = document.createElement('iframe'); + t.add_cleanup(() => iframe.remove()); + + iframe.src = genUrl(outer); + iframe.addEventListener('load', () => { + const w = iframe.contentWindow; + const d = iframe.contentDocument; + const nested = d.createElement('iframe'); + nested.src = genUrl(inner) + '-nested'; + d.body.appendChild(nested); + }, {once: true}); + document.body.appendChild(iframe); + } + } + + // Wait 3 seconds for reports to settle. + await wait(3000); + + function check(rs, inner, outer) { + checkNavigationReportExistence( + rs, genUrl(inner) + '-nested', genUrl(outer)); + } + function checkNoReport(reports, inner, outer) { + checkReportNonExistence( + reports, genUrl(inner) + '-nested', genUrl(outer)); + } + + // outer === noCoep + checkNoReport(reports, noCoep, noCoep); + checkNoReport(reports, coep, noCoep); + checkNoReport(reports, coepReportOnly, noCoep); + checkNoReport(reportsForReportOnly, noCoep, noCoep); + checkNoReport(reportsForReportOnly, coep, noCoep); + checkNoReport(reportsForReportOnly, coepReportOnly, noCoep); + + // outer === coep + check(reports, noCoep, coep); + checkNoReport(reports, coep, coep); + check(reports, coepReportOnly, coep); + checkNoReport(reportsForReportOnly, noCoep, coep); + checkNoReport(reportsForReportOnly, coep, coep); + checkNoReport(reportsForReportOnly, coepReportOnly, coep); + + // outer === coepReportOnly + checkNoReport(reports, noCoep, coepReportOnly); + checkNoReport(reports, coep, coepReportOnly); + checkNoReport(reports, coepReportOnly, coepReportOnly); + check(reportsForReportOnly, noCoep, coepReportOnly); + checkNoReport(reportsForReportOnly, coep, coepReportOnly); + check(reportsForReportOnly, coepReportOnly, coepReportOnly); + + t.done(); + } catch (e) { + t.step(() => { throw e }); + } +}, 'COEP violation on nested frame navigation'); + +</script>$
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/service-worker-cache-storage.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/service-worker-cache-storage.https-expected.txt deleted file mode 100644 index 10fe541..0000000 --- a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/service-worker-cache-storage.https-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -PASS A ServiceWorker with coep-none use CacheStorage to get a corp-undefined response. -PASS A ServiceWorker with coep-none use CacheStorage to get a corp-cross-origin response. -FAIL A ServiceWorker with coep-require-corp use CacheStorage to get a corp-undefined response. assert_equals: expected false but got true -PASS A ServiceWorker with coep-require-corp use CacheStorage to get a corp-cross-origin response. -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-timeline-phases.tentative.html b/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-timeline-phases.tentative.html index 0cc4e128..48ca749 100644 --- a/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-timeline-phases.tentative.html +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-timeline-phases.tentative.html
@@ -22,13 +22,165 @@ promise_test(async t => { const timeline = createScrollTimeline(t); - assert_equals(timeline.phase, "inactive"); - }, 'Scroll timeline starts in "inactive" phase.'); - - promise_test(async t => { - const timeline = createScrollTimeline(t); assert_throws_js(TypeError, () => { timeline.phase = "after"; }); }, 'Setting scroll timeline phase (which is readonly) throws TypeError.'); + + const test_cases = { + before_start: { + name: "before start", + scroll_percent: 0.1, + timeline_phase: "before" + }, + at_start: { + name: "at start", + scroll_percent: 0.2, + timeline_phase: "active" + }, + in_range: { + name: "in range", + scroll_percent: 0.5, + timeline_phase: "active" + }, + at_end: { + name: "at end", + scroll_percent: 0.8, + timeline_phase: "after" + }, + after_end: { + name: "after end", + scroll_percent: 0.9, + timeline_phase: "after" + } + } + + for (const test_case_key in test_cases){ + const test_case = test_cases[test_case_key]; + test(t => { + const timeline = createScrollTimelineWithOffsets(t, "20%", "80%"); + const scroller = timeline.scrollSource; + const maxScroll = scroller.scrollHeight - scroller.clientHeight; + + scroller.scrollTop = test_case.scroll_percent * maxScroll; + + assert_equals( + timeline.phase, + test_case.timeline_phase, + "timeline.phase" + ); + }, "Timeline phase while scroll offset is " + test_case.name); + } + + // TODO(crbug.com/1060384): Spec is unclear in this case, revisit this when + // desired results have been established. + // These test cases are worded strangely because they test an edge case + // where startScrollOffset is GREATER THAN endScrollOffset + const test_cases_start_offset_greater_than_end_offset = { + before_end: { + name: "before end", + scroll_percent: 0.1, + timeline_phase: "before" + }, + at_end: { + name: "at end", + scroll_percent: 0.2, + timeline_phase: "before" + }, + before_start: { + name: "before start", + scroll_percent: 0.5, + timeline_phase: "before" + }, + at_start: { + name: "at start", + scroll_percent: 0.8, + timeline_phase: "after" + }, + after_start: { + name: "after start", + scroll_percent: 0.9, + timeline_phase: "after" + } + } + + for (const test_case_key in test_cases_start_offset_greater_than_end_offset){ + const test_case = + test_cases_start_offset_greater_than_end_offset[test_case_key]; + test(t => { + const timeline = createScrollTimelineWithOffsets(t, "80%", "20%"); + const scroller = timeline.scrollSource; + const maxScroll = scroller.scrollHeight - scroller.clientHeight; + + scroller.scrollTop = test_case.scroll_percent * maxScroll; + + assert_equals( + timeline.phase, + test_case.timeline_phase, + "timeline.phase" + ); + }, "Timeline phase while start offset is greater than end offset and" + + " scroll offset is " + test_case.name); + } + + // TODO(crbug.com/1060384): Spec is unclear in this case, revisit this when + // desired results have been established. + // Test cases where startScrollOffset is EQUAL TO endScrollOffset + const test_cases_start_offset_equal_to_end_offset = { + before_end: { + name: "before start", + scroll_percent: 0.3, + timeline_phase: "before" + }, + at_end: { + name: "at both", + scroll_percent: 0.5, + timeline_phase: "after" + }, + before_start: { + name: "after end", + scroll_percent: 0.7, + timeline_phase: "after" + } + } + + for (const test_case_key in test_cases_start_offset_equal_to_end_offset){ + const test_case = + test_cases_start_offset_equal_to_end_offset[test_case_key]; + test(t => { + const timeline = createScrollTimelineWithOffsets(t, "50%", "50%"); + const scroller = timeline.scrollSource; + const maxScroll = scroller.scrollHeight - scroller.clientHeight; + + scroller.scrollTop = test_case.scroll_percent * maxScroll; + + assert_equals( + timeline.phase, + test_case.timeline_phase, + "timeline.phase" + ); + }, "Timeline phase while start offset is equal to end offset and scroll" + + " offset is " + test_case.name); + } + + test(t => { + const timeline = createScrollTimeline(t); + const scroller = timeline.scrollSource; + // Timeline should be inactive since layout hasn't updated yet + assert_equals(timeline.phase, "inactive"); + + // Accessing scroller.scrollHeight forces the scroller to update + scroller.scrollHeight; + assert_equals(timeline.phase, "active"); + + // Setting the scroller to display none should make the timeline inactive + scroller.style.display = "none" + + // Force another layout + scroller.scrollHeight; + + assert_equals(timeline.phase, "inactive"); + }, 'Scroll timeline starts inactive, can transition to active, and then' + + ' back to inactive.'); + </script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/testcommon.js b/third_party/blink/web_tests/external/wpt/scroll-animations/testcommon.js index ca2596885..ab22ff6 100644 --- a/third_party/blink/web_tests/external/wpt/scroll-animations/testcommon.js +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/testcommon.js
@@ -12,6 +12,16 @@ }); } +function createScrollTimelineWithOffsets(test, startOffset, endOffset) { + return new ScrollTimeline({ + scrollSource: createScroller(test), + orientation: "vertical", + startScrollOffset: startOffset, + endScrollOffset: endOffset, + timeRange: 1000 + }); +} + function createScrollLinkedAnimation(test, timeline) { if(timeline === undefined) timeline = createScrollTimeline(test);
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/slots-imperative-slot-api.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/shadow-dom/slots-imperative-slot-api.tentative-expected.txt index 9dc356fbc..79d2a7d1 100644 --- a/third_party/blink/web_tests/external/wpt/shadow-dom/slots-imperative-slot-api.tentative-expected.txt +++ b/third_party/blink/web_tests/external/wpt/shadow-dom/slots-imperative-slot-api.tentative-expected.txt
@@ -1,6 +1,5 @@ This is a testharness.js-based test. -FAIL attachShadow can take slotAssignment parameter. assert_throws_js: others should throw exception function "() => { - tTree.host3.attachShadow({ mode: 'open', slotAssignment: 'exceptional' })}" did not throw +PASS attachShadow can take slotAssignment parameter. FAIL Imperative slot API throws exception when not slotAssignment != 'manual'. assert_throws_dom: function "() => { tTree.s1.assign([]); }" did not throw FAIL Imperative slot API throws exception when slotable parentNode != slot's host. assert_throws_dom: function "() => { tTree.s2.assign([tTree.c1]); }" did not throw FAIL Imperative slot API can assign nodes in manual slot assignment. assert_equals: expected null but got Element node <slot id="s1"></slot>
diff --git a/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt b/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt index a478015..988ffe8 100644 --- a/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt +++ b/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt
@@ -1,3 +1,3 @@ -mypy==0.761 +mypy==0.770 mypy-extensions==0.4.3 typed-ast==1.4.1
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_firefox.txt b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_firefox.txt index ae7294081..d541a49 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_firefox.txt +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_firefox.txt
@@ -3,9 +3,9 @@ mozdownload==1.26.0 mozinstall==2.0.0 mozleak==0.2 -moznetwork==0.27 +moznetwork==1.1.0 mozprocess==1.0.0 -mozprofile==2.4.0 +mozprofile==2.5.0 mozrunner==7.7.0 -mozversion==2.2.0 +mozversion==2.3.0 psutil==5.7.0
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/idlharness.window-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/idlharness.window-expected.txt deleted file mode 100644 index 444ec5d..0000000 --- a/third_party/blink/web_tests/external/wpt/web-animations/idlharness.window-expected.txt +++ /dev/null
@@ -1,147 +0,0 @@ -This is a testharness.js-based test. -Found 143 tests; 141 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS idl_test setup -PASS idl_test validation -PASS Partial interface Document: original interface defined -PASS Partial interface Document: member names are unique -PASS Partial interface mixin DocumentOrShadowRoot: original interface mixin defined -PASS Partial interface mixin DocumentOrShadowRoot: member names are unique -PASS Partial interface Document[2]: member names are unique -PASS Partial interface Document[3]: member names are unique -PASS Element includes Animatable: member names are unique -PASS Element includes ParentNode: member names are unique -PASS Element includes NonDocumentTypeChildNode: member names are unique -PASS Element includes ChildNode: member names are unique -PASS Element includes Slotable: member names are unique -PASS Document includes NonElementParentNode: member names are unique -PASS Document includes DocumentOrShadowRoot: member names are unique -PASS Document includes ParentNode: member names are unique -PASS Document includes XPathEvaluatorBase: member names are unique -PASS Document includes GlobalEventHandlers: member names are unique -PASS Document includes DocumentAndElementEventHandlers: member names are unique -PASS DocumentFragment includes NonElementParentNode: member names are unique -PASS DocumentFragment includes ParentNode: member names are unique -PASS ShadowRoot includes DocumentOrShadowRoot: member names are unique -PASS AnimationTimeline interface: existence and properties of interface object -PASS AnimationTimeline interface object length -PASS AnimationTimeline interface object name -PASS AnimationTimeline interface: existence and properties of interface prototype object -PASS AnimationTimeline interface: existence and properties of interface prototype object's "constructor" property -PASS AnimationTimeline interface: existence and properties of interface prototype object's @@unscopables property -PASS AnimationTimeline interface: attribute currentTime -PASS DocumentTimeline interface: existence and properties of interface object -PASS DocumentTimeline interface object length -PASS DocumentTimeline interface object name -PASS DocumentTimeline interface: existence and properties of interface prototype object -PASS DocumentTimeline interface: existence and properties of interface prototype object's "constructor" property -PASS DocumentTimeline interface: existence and properties of interface prototype object's @@unscopables property -PASS DocumentTimeline must be primary interface of document.timeline -PASS Stringification of document.timeline -PASS AnimationTimeline interface: document.timeline must inherit property "currentTime" with the proper type -PASS Animation interface: existence and properties of interface object -PASS Animation interface object length -PASS Animation interface object name -PASS Animation interface: existence and properties of interface prototype object -PASS Animation interface: existence and properties of interface prototype object's "constructor" property -PASS Animation interface: existence and properties of interface prototype object's @@unscopables property -PASS Animation interface: attribute id -PASS Animation interface: attribute effect -PASS Animation interface: attribute timeline -PASS Animation interface: attribute startTime -PASS Animation interface: attribute currentTime -PASS Animation interface: attribute playbackRate -PASS Animation interface: attribute playState -PASS Animation interface: attribute replaceState -PASS Animation interface: attribute pending -PASS Animation interface: attribute ready -PASS Animation interface: attribute finished -PASS Animation interface: attribute onfinish -PASS Animation interface: attribute oncancel -PASS Animation interface: attribute onremove -PASS Animation interface: operation cancel() -PASS Animation interface: operation finish() -PASS Animation interface: operation play() -PASS Animation interface: operation pause() -PASS Animation interface: operation updatePlaybackRate(double) -PASS Animation interface: operation reverse() -PASS Animation interface: operation persist() -PASS Animation interface: operation commitStyles() -PASS Animation must be primary interface of new Animation() -PASS Stringification of new Animation() -PASS Animation interface: new Animation() must inherit property "id" with the proper type -PASS Animation interface: new Animation() must inherit property "effect" with the proper type -PASS Animation interface: new Animation() must inherit property "timeline" with the proper type -PASS Animation interface: new Animation() must inherit property "startTime" with the proper type -PASS Animation interface: new Animation() must inherit property "currentTime" with the proper type -PASS Animation interface: new Animation() must inherit property "playbackRate" with the proper type -PASS Animation interface: new Animation() must inherit property "playState" with the proper type -PASS Animation interface: new Animation() must inherit property "replaceState" with the proper type -PASS Animation interface: new Animation() must inherit property "pending" with the proper type -PASS Animation interface: new Animation() must inherit property "ready" with the proper type -PASS Animation interface: new Animation() must inherit property "finished" with the proper type -PASS Animation interface: new Animation() must inherit property "onfinish" with the proper type -PASS Animation interface: new Animation() must inherit property "oncancel" with the proper type -PASS Animation interface: new Animation() must inherit property "onremove" with the proper type -PASS Animation interface: new Animation() must inherit property "cancel()" with the proper type -PASS Animation interface: new Animation() must inherit property "finish()" with the proper type -PASS Animation interface: new Animation() must inherit property "play()" with the proper type -PASS Animation interface: new Animation() must inherit property "pause()" with the proper type -PASS Animation interface: new Animation() must inherit property "updatePlaybackRate(double)" with the proper type -PASS Animation interface: calling updatePlaybackRate(double) on new Animation() with too few arguments must throw TypeError -PASS Animation interface: new Animation() must inherit property "reverse()" with the proper type -PASS Animation interface: new Animation() must inherit property "persist()" with the proper type -PASS Animation interface: new Animation() must inherit property "commitStyles()" with the proper type -PASS AnimationEffect interface: existence and properties of interface object -PASS AnimationEffect interface object length -PASS AnimationEffect interface object name -PASS AnimationEffect interface: existence and properties of interface prototype object -PASS AnimationEffect interface: existence and properties of interface prototype object's "constructor" property -PASS AnimationEffect interface: existence and properties of interface prototype object's @@unscopables property -PASS AnimationEffect interface: operation getTiming() -PASS AnimationEffect interface: operation getComputedTiming() -PASS AnimationEffect interface: operation updateTiming(optional OptionalEffectTiming) -PASS KeyframeEffect interface: existence and properties of interface object -PASS KeyframeEffect interface object length -PASS KeyframeEffect interface object name -PASS KeyframeEffect interface: existence and properties of interface prototype object -PASS KeyframeEffect interface: existence and properties of interface prototype object's "constructor" property -PASS KeyframeEffect interface: existence and properties of interface prototype object's @@unscopables property -PASS KeyframeEffect interface: attribute target -PASS KeyframeEffect interface: attribute pseudoElement -PASS KeyframeEffect interface: attribute composite -PASS KeyframeEffect interface: operation getKeyframes() -PASS KeyframeEffect interface: operation setKeyframes(object?) -PASS KeyframeEffect must be primary interface of new KeyframeEffect(null, null) -PASS Stringification of new KeyframeEffect(null, null) -PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "target" with the proper type -PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "pseudoElement" with the proper type -PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "composite" with the proper type -PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "getKeyframes()" with the proper type -PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "setKeyframes(object?)" with the proper type -PASS KeyframeEffect interface: calling setKeyframes(object?) on new KeyframeEffect(null, null) with too few arguments must throw TypeError -PASS AnimationEffect interface: new KeyframeEffect(null, null) must inherit property "getTiming()" with the proper type -PASS AnimationEffect interface: new KeyframeEffect(null, null) must inherit property "getComputedTiming()" with the proper type -PASS AnimationEffect interface: new KeyframeEffect(null, null) must inherit property "updateTiming(optional OptionalEffectTiming)" with the proper type -PASS AnimationEffect interface: calling updateTiming(optional OptionalEffectTiming) on new KeyframeEffect(null, null) with too few arguments must throw TypeError -PASS AnimationPlaybackEvent interface: existence and properties of interface object -PASS AnimationPlaybackEvent interface object length -PASS AnimationPlaybackEvent interface object name -PASS AnimationPlaybackEvent interface: existence and properties of interface prototype object -PASS AnimationPlaybackEvent interface: existence and properties of interface prototype object's "constructor" property -PASS AnimationPlaybackEvent interface: existence and properties of interface prototype object's @@unscopables property -PASS AnimationPlaybackEvent interface: attribute currentTime -PASS AnimationPlaybackEvent interface: attribute timelineTime -PASS AnimationPlaybackEvent must be primary interface of new AnimationPlaybackEvent("cancel") -PASS Stringification of new AnimationPlaybackEvent("cancel") -PASS AnimationPlaybackEvent interface: new AnimationPlaybackEvent("cancel") must inherit property "currentTime" with the proper type -PASS AnimationPlaybackEvent interface: new AnimationPlaybackEvent("cancel") must inherit property "timelineTime" with the proper type -PASS Document interface: attribute timeline -PASS Document interface: operation getAnimations() -PASS Document interface: document must inherit property "timeline" with the proper type -PASS Document interface: document must inherit property "getAnimations()" with the proper type -FAIL ShadowRoot interface: operation getAnimations() assert_own_property: interface prototype object missing non-static operation expected property "getAnimations" missing -FAIL ShadowRoot interface: shadowRoot must inherit property "getAnimations()" with the proper type assert_inherits: property "getAnimations" not found in prototype chain -PASS Element interface: operation animate(object?, optional (unrestricted double or KeyframeAnimationOptions)) -PASS Element interface: operation getAnimations(optional GetAnimationsOptions) -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/DocumentOrShadowRoot/getAnimations-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/DocumentOrShadowRoot/getAnimations-expected.txt deleted file mode 100644 index d198587..0000000 --- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/DocumentOrShadowRoot/getAnimations-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -PASS Document.getAnimations() returns an empty sequence for non-animated content -PASS Document.getAnimations() returns script-generated animations -PASS Document.getAnimations() returns script-generated animations in the order they were created -PASS Document.getAnimations() does not return a disconnected node -PASS Document.getAnimations() does not return an animation with a null target -PASS Document.getAnimations() returns animations on elements inside same-origin iframes -PASS iframe.contentDocument.getAnimations() returns animations on elements inside same-origin Document -FAIL ShadowRoot.getAnimations() return all animations in the shadow tree div.shadowRoot.getAnimations is not a function -FAIL Document.getAnimations() does NOT return animations in shadow trees assert_array_equals: getAnimations() called on Document does not return animations from shadow trees lengths differ, expected array [] length 0, got [object "[object Animation]"] length 1 -PASS Document.getAnimations() triggers a style change event -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/DocumentOrShadowRoot/getAnimations.html b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/DocumentOrShadowRoot/getAnimations.html index 5d6952b..67addc0 100644 --- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/DocumentOrShadowRoot/getAnimations.html +++ b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/DocumentOrShadowRoot/getAnimations.html
@@ -188,6 +188,20 @@ ); }, 'Document.getAnimations() does NOT return animations in shadow trees'); +test(t => { + const div = createDiv(t); + const shadow = div.attachShadow({ mode: 'open' }); + + div.animate(gKeyFrames, 100 * MS_PER_SEC) + + assert_array_equals( + div.shadowRoot.getAnimations(), + [], + 'getAnimations() called on ShadowRoot does not return animations from' + + ' Document' + ); +}, 'ShadowRoot.getAnimations() does NOT return animations in parent document'); + promise_test(async t => { const div = createDiv(t); const watcher = EventWatcher(t, div, 'transitionrun');
diff --git a/third_party/blink/web_tests/fast/css-generated-content/pseudo-element-cursor-expected.txt b/third_party/blink/web_tests/fast/css-generated-content/pseudo-element-cursor-expected.txt index 446e176..88bb9781 100644 --- a/third_party/blink/web_tests/fast/css-generated-content/pseudo-element-cursor-expected.txt +++ b/third_party/blink/web_tests/fast/css-generated-content/pseudo-element-cursor-expected.txt
@@ -2,7 +2,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -Cursor Info: type=Wait hotSpot=0,0 +Cursor Info: type=Wait PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/blink/web_tests/fast/dom/shadow/anchor-content-projected-expected.txt b/third_party/blink/web_tests/fast/dom/shadow/anchor-content-projected-expected.txt index badd40b..fa5cec05 100644 --- a/third_party/blink/web_tests/fast/dom/shadow/anchor-content-projected-expected.txt +++ b/third_party/blink/web_tests/fast/dom/shadow/anchor-content-projected-expected.txt
@@ -3,7 +3,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand PASS window.location.hash is "#link-clicked" PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/events/mouse-cursor-change-after-image-load.html b/third_party/blink/web_tests/fast/events/mouse-cursor-change-after-image-load.html index 031e576..6572e35 100644 --- a/third_party/blink/web_tests/fast/events/mouse-cursor-change-after-image-load.html +++ b/third_party/blink/web_tests/fast/events/mouse-cursor-change-after-image-load.html
@@ -18,7 +18,7 @@ cursorTest.step(function() { assert_not_equals(window.eventSender, undefined, 'This test requires eventSender.'); - assert_equals(internals.getCurrentCursorInfo(), "type=Pointer hotSpot=0,0"); + assert_equals(internals.getCurrentCursorInfo(), "type=Pointer"); var target = document.getElementById('target'); var rect = target.getBoundingClientRect();
diff --git a/third_party/blink/web_tests/fast/events/mouse-cursor-change-expected.txt b/third_party/blink/web_tests/fast/events/mouse-cursor-change-expected.txt index d81f8bf..04b0c94 100644 --- a/third_party/blink/web_tests/fast/events/mouse-cursor-change-expected.txt +++ b/third_party/blink/web_tests/fast/events/mouse-cursor-change-expected.txt
@@ -7,19 +7,19 @@ Mouse move -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand Mouse down -Cursor Info: type=Progress hotSpot=0,0 +Cursor Info: type=Progress Mouse hold down, move -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand Mouse up -Cursor Info: type=Help hotSpot=0,0 +Cursor Info: type=Help PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/events/mouse-cursor-expected.txt b/third_party/blink/web_tests/fast/events/mouse-cursor-expected.txt index 0ef9c7f..b9b116ea 100644 --- a/third_party/blink/web_tests/fast/events/mouse-cursor-expected.txt +++ b/third_party/blink/web_tests/fast/events/mouse-cursor-expected.txt
@@ -7,47 +7,47 @@ TEST CASE: Implicit default cursor -Cursor Info: type=IBeam hotSpot=0,0 +Cursor Info: type=IBeam TEST CASE: Explicit default -Cursor Info: type=Pointer hotSpot=0,0 +Cursor Info: type=Pointer TEST CASE: Explicit auto -Cursor Info: type=IBeam hotSpot=0,0 +Cursor Info: type=IBeam TEST CASE: No cursor -Cursor Info: type=None hotSpot=0,0 +Cursor Info: type=None TEST CASE: Pointer -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: grab -Cursor Info: type=Grab hotSpot=0,0 +Cursor Info: type=Grab TEST CASE: grabbing -Cursor Info: type=Grabbing hotSpot=0,0 +Cursor Info: type=Grabbing TEST CASE: -webkit-grab -Cursor Info: type=Grab hotSpot=0,0 +Cursor Info: type=Grab TEST CASE: -webkit-grabbing -Cursor Info: type=Grabbing hotSpot=0,0 +Cursor Info: type=Grabbing TEST CASE: Existing 25x25 image -Cursor Info: type=IBeam hotSpot=0,0 +Cursor Info: type=IBeam TEST CASE: Invalid URL with fallback to pointer -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: Invalid with fallback to 25x25 image @@ -83,31 +83,31 @@ TEST CASE: Over large image with fallback to pointer -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: Local element reference -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: Multiple invalid cursors with fallback to pointer -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: Nonexistent local element reference with fallback to pointer -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: A link with default cursor -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: Link with default cursor overriding wait -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: Wait cursor which should not be affected by unknown cursor rule -Cursor Info: type=Wait hotSpot=0,0 +Cursor Info: type=Wait PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/events/mouse-cursor-image-set-expected.txt b/third_party/blink/web_tests/fast/events/mouse-cursor-image-set-expected.txt index 5b852a1..efac1960 100644 --- a/third_party/blink/web_tests/fast/events/mouse-cursor-image-set-expected.txt +++ b/third_party/blink/web_tests/fast/events/mouse-cursor-image-set-expected.txt
@@ -25,11 +25,11 @@ TEST CASE: Invalid tiny scale with fallback to pointer -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: Over-large image with fallback to pointer -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: 200x200 image at 4x (not over-large in UI pixels) @@ -71,11 +71,11 @@ TEST CASE: Invalid tiny scale with fallback to pointer -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: Over-large image with fallback to pointer -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand TEST CASE: 200x200 image at 4x (not over-large in UI pixels)
diff --git a/third_party/blink/web_tests/fast/events/mouse-cursor-multiframecur-expected.txt b/third_party/blink/web_tests/fast/events/mouse-cursor-multiframecur-expected.txt index 0e64289a..f6cbe55 100644 --- a/third_party/blink/web_tests/fast/events/mouse-cursor-multiframecur-expected.txt +++ b/third_party/blink/web_tests/fast/events/mouse-cursor-multiframecur-expected.txt
@@ -7,7 +7,7 @@ TEST CASE: Implicit default cursor -Cursor Info: type=IBeam hotSpot=0,0 +Cursor Info: type=IBeam TEST CASE: CUR file with 3 frames, largest of which (2nd frame) is 20x12 with hotspot at (18,11).
diff --git a/third_party/blink/web_tests/fast/events/mouse-cursor-no-mousemove-expected.txt b/third_party/blink/web_tests/fast/events/mouse-cursor-no-mousemove-expected.txt index 42d1dc5..9c2b154d 100644 --- a/third_party/blink/web_tests/fast/events/mouse-cursor-no-mousemove-expected.txt +++ b/third_party/blink/web_tests/fast/events/mouse-cursor-no-mousemove-expected.txt
@@ -7,8 +7,8 @@ TEST CASE: Mouse idle, change cursor should not fire mousemove event -Cursor Info: type=Pointer hotSpot=0,0 -Cursor Info: type=Help hotSpot=0,0 +Cursor Info: type=Pointer +Cursor Info: type=Help PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/events/mouse-cursor-style-change-iframe-expected.txt b/third_party/blink/web_tests/fast/events/mouse-cursor-style-change-iframe-expected.txt index 4621ac5..6a41d9e 100644 --- a/third_party/blink/web_tests/fast/events/mouse-cursor-style-change-iframe-expected.txt +++ b/third_party/blink/web_tests/fast/events/mouse-cursor-style-change-iframe-expected.txt
@@ -3,18 +3,18 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". Mouse moved to cursor changing div -PASS internals.getCurrentCursorInfo() is "type=Hand hotSpot=0,0" +PASS internals.getCurrentCursorInfo() is "type=Hand" Changing cursor style -PASS internals.getCurrentCursorInfo() is "type=Wait hotSpot=0,0" +PASS internals.getCurrentCursorInfo() is "type=Wait" Now move mouse onto iframe above cursor changing div PASS document.elementFromPoint(100, y) is frame PASS document.elementsFromPoint(100, y).indexOf(container) > 0 is true PASS internals.cursorUpdatePending is false -PASS internals.getCurrentCursorInfo() is "type=IBeam hotSpot=0,0" +PASS internals.getCurrentCursorInfo() is "type=IBeam" Changing cursor style of the background should not affect the cursor as it sits over the iframe -PASS internals.getCurrentCursorInfo() is "type=IBeam hotSpot=0,0" +PASS internals.getCurrentCursorInfo() is "type=IBeam" PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/blink/web_tests/fast/events/mouse-cursor-style-change-iframe.html b/third_party/blink/web_tests/fast/events/mouse-cursor-style-change-iframe.html index 690d401..d172ef47 100644 --- a/third_party/blink/web_tests/fast/events/mouse-cursor-style-change-iframe.html +++ b/third_party/blink/web_tests/fast/events/mouse-cursor-style-change-iframe.html
@@ -46,11 +46,11 @@ frame.onload = function() { debug('Mouse moved to cursor changing div'); eventSender.mouseMoveTo(100, container.offsetTop + 5); - shouldBeEqualToString('internals.getCurrentCursorInfo()', 'type=Hand hotSpot=0,0'); + shouldBeEqualToString('internals.getCurrentCursorInfo()', 'type=Hand'); debug('Changing cursor style'); container.classList.add('wait'); - expectCursorUpdate('type=Wait hotSpot=0,0', function() { + expectCursorUpdate('type=Wait', function() { debug(''); debug('Now move mouse onto iframe above cursor changing div'); @@ -59,12 +59,12 @@ shouldBe('document.elementFromPoint(100, y)', 'frame'); shouldBeTrue('document.elementsFromPoint(100, y).indexOf(container) > 0'); shouldBeFalse('internals.cursorUpdatePending'); - shouldBeEqualToString('internals.getCurrentCursorInfo()', 'type=IBeam hotSpot=0,0'); + shouldBeEqualToString('internals.getCurrentCursorInfo()', 'type=IBeam'); debug(''); debug('Changing cursor style of the background should not affect the cursor as it sits over the iframe'); container.classList.remove('wait'); - expectCursorUpdate('type=IBeam hotSpot=0,0', function() { + expectCursorUpdate('type=IBeam', function() { finishJSTest(); }); });
diff --git a/third_party/blink/web_tests/fast/events/mousemove-to-resizer-changes-cursor-expected.txt b/third_party/blink/web_tests/fast/events/mousemove-to-resizer-changes-cursor-expected.txt index 6b99460..0ad1f568 100644 --- a/third_party/blink/web_tests/fast/events/mousemove-to-resizer-changes-cursor-expected.txt +++ b/third_party/blink/web_tests/fast/events/mousemove-to-resizer-changes-cursor-expected.txt
@@ -1,7 +1,7 @@ This tests that hovering over a TEXTAREA resizer turns the mouse cursor into the SouthEastResize cursor. -Inside TEXTAREA: type=IBeam hotSpot=0,0 -Over dragger: type=SouthEastResize hotSpot=0,0 -Over BODY: type=Hand hotSpot=0,0 -Over dragger: type=SouthEastResize hotSpot=0,0 +Inside TEXTAREA: type=IBeam +Over dragger: type=SouthEastResize +Over BODY: type=Hand +Over dragger: type=SouthEastResize
diff --git a/third_party/blink/web_tests/fast/events/mousemove-to-scrollbar-changes-cursor-expected.txt b/third_party/blink/web_tests/fast/events/mousemove-to-scrollbar-changes-cursor-expected.txt index bffc478..b553fbf 100644 --- a/third_party/blink/web_tests/fast/events/mousemove-to-scrollbar-changes-cursor-expected.txt +++ b/third_party/blink/web_tests/fast/events/mousemove-to-scrollbar-changes-cursor-expected.txt
@@ -1,4 +1,4 @@ This tests that hovering over a scrollbar resets the mouse cursor to the default pointer. -Hovered pointer: type=Hand hotSpot=0,0 -Scrollbar pointer: type=Pointer hotSpot=0,0 +Hovered pointer: type=Hand +Scrollbar pointer: type=Pointer
diff --git a/third_party/blink/web_tests/fast/events/resources/middleClickAutoscroll.js b/third_party/blink/web_tests/fast/events/resources/middleClickAutoscroll.js index 113200a..90b8ceab 100644 --- a/third_party/blink/web_tests/fast/events/resources/middleClickAutoscroll.js +++ b/third_party/blink/web_tests/fast/events/resources/middleClickAutoscroll.js
@@ -56,8 +56,7 @@ // Wait for the cursor shape to go back to normal. await waitFor(() => { var cursorInfo = internals.getCurrentCursorInfo(); - return cursorInfo == "type=Pointer hotSpot=0,0" || - cursorInfo == "type=IBeam hotSpot=0,0"; + return cursorInfo == "type=Pointer" || cursorInfo == "type=IBeam"; }); finishTest();
diff --git a/third_party/blink/web_tests/fast/events/update-mouse-cursor-after-layout-change.html b/third_party/blink/web_tests/fast/events/update-mouse-cursor-after-layout-change.html index 77da1773..90e40a8 100644 --- a/third_party/blink/web_tests/fast/events/update-mouse-cursor-after-layout-change.html +++ b/third_party/blink/web_tests/fast/events/update-mouse-cursor-after-layout-change.html
@@ -42,9 +42,9 @@ var target = document.getElementById('target'); var rect = target.getBoundingClientRect(); await mouseMoveTo(rect.left + 3, rect.top + 3); - assert_equals(internals.getCurrentCursorInfo(), 'type=IBeam hotSpot=0,0', 'wait for move to target'); + assert_equals(internals.getCurrentCursorInfo(), 'type=IBeam', 'wait for move to target'); await mouseClickOn(rect.left + 3, rect.top + 3); - assert_equals(internals.getCurrentCursorInfo(), 'type=Wait hotSpot=0,0', 'wait for mouse cursor change'); + assert_equals(internals.getCurrentCursorInfo(), 'type=Wait', 'wait for mouse cursor change'); }, 'Tests that there is mouse cursor update when the element underneath the mouse cursor is changed.'); } -</script> \ No newline at end of file +</script>
diff --git a/third_party/blink/web_tests/fast/inline/middle-continuation-inherits-visibility-from-inline-parent.html b/third_party/blink/web_tests/fast/inline/middle-continuation-inherits-visibility-from-inline-parent.html index 461478a..123f8ac 100644 --- a/third_party/blink/web_tests/fast/inline/middle-continuation-inherits-visibility-from-inline-parent.html +++ b/third_party/blink/web_tests/fast/inline/middle-continuation-inherits-visibility-from-inline-parent.html
@@ -15,7 +15,7 @@ eventSender.dragMode = false; eventSender.mouseMoveTo(10, 10); var originalInfo = internals.getCurrentCursorInfo(); - assert_equals(originalInfo, "type=Pointer hotSpot=0,0"); + assert_equals(originalInfo, "type=Pointer"); } }, 'crbug.com/706324: Middle continuations should inherit the style of their inline parent, so when the cursor is placed over the anonymous block it should remain a pointer.'); </script>
diff --git a/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-insertable-streams.html b/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-insertable-streams.html new file mode 100644 index 0000000..dc170e5e --- /dev/null +++ b/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-insertable-streams.html
@@ -0,0 +1,167 @@ +<!DOCTYPE html> +<html> +<head> +<title>RTCPeerConnection.getRemoteStreams</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../../external/wpt/webrtc/RTCPeerConnection-helper.js"> +</script></head> +<body> +<script> +// TODO(crbug.com/1058021): Move this test to external/wpt/webrtc/ once the +// Insertable Streams spec is mature enough. + +function areArrayBuffersEqual(buffer1, buffer2) +{ + if (buffer1.byteLength != buffer2.byteLength) + return false; + let array1 = new Int8Array(buffer1); + var array2 = new Int8Array(buffer2); + for (let i = 0 ; i < buffer1.byteLength ; ++i) { + if (array1[i] != array2[i]) + return false; + } + return true; +} + +promise_test(async t => { + const caller = new RTCPeerConnection({forceEncodedVideoInsertableStreams:true}); + t.add_cleanup(() => caller.close()); + const callee = new RTCPeerConnection({forceEncodedVideoInsertableStreams:true}); + t.add_cleanup(() => callee.close()); + + const stream = await navigator.mediaDevices.getUserMedia({video:true}); + const videoTrack = stream.getVideoTracks()[0]; + t.add_cleanup(() => videoTrack.stop()); + + const videoSender = caller.addTrack(videoTrack) + const senderStreams = videoSender.createEncodedVideoStreams(); + const senderReader = senderStreams.readableStream.getReader(); + const senderWriter = senderStreams.writableStream.getWriter(); + + const frames = []; + const numFramesPassthrough = 5; + const numFramesReplaceData = 5; + const numFramesModifyData = 5; + const numFramesToSend = numFramesPassthrough + numFramesReplaceData + numFramesModifyData; + + const ontrackPromise = new Promise(resolve => { + callee.ontrack = t.step_func(() => { + const receivers = callee.getReceivers(); + let videoReceiver = null; + for (const r of receivers) { + if (r.track.kind == 'video') + videoReceiver = r; + } + assert_true(videoReceiver !== undefined); + + const receiverStreams = + videoReceiver.createEncodedVideoStreams(); + const receiverReader = receiverStreams.readableStream.getReader(); + const receiverWriter = receiverStreams.writableStream.getWriter(); + + // The WebRTC stack may occassionally deliver duplicate frames on the + // receiver side, therefore start twice as many read attempts as sent + // frames to account for this. + const maxFramesToReceive = numFramesToSend * 2; + let numVerifiedFrames = 0; + for (let i = 0; i < maxFramesToReceive; i++) { + receiverReader.read().then(t.step_func(result => { + if (frames[numVerifiedFrames] && + areArrayBuffersEqual(result.value.data, frames[numVerifiedFrames])) { + numVerifiedFrames++; + } else if (frames[numVerifiedFrames-1] && + areArrayBuffersEqual(result.value.data, frames[numVerifiedFrames-1])) { + // Duplicate frame. It can happen occassionally. Ignore. + } else { + // Receiving unexpected (nonduplicate) frames is an indication that + // frames are not passed correctly between sender and receiver. + assert_unreached("Incorrect frame received"); + } + + if (numVerifiedFrames == numFramesToSend) + resolve(); + })); + } + }); + }); + + exchangeIceCandidates(caller, callee); + await doSignalingHandshake(caller, callee); + // Pass frames as they come from the encoder. + for (let i = 0; i < numFramesPassthrough; i++) { + const result = await senderReader.read() + frames.push(result.value.data); + senderWriter.write(result.value); + } + + // Replace frame data with arbitrary buffers. + for (let i = 0; i < numFramesReplaceData; i++) { + const result = await senderReader.read() + + const buffer = new ArrayBuffer(100); + const int8View = new Int8Array(buffer); + int8View.fill(i); + + result.value.data = buffer; + frames.push(result.value.data); + senderWriter.write(result.value); + } + + // Modify frame data. + for (let i = 0; i < numFramesReplaceData; i++) { + const result = await senderReader.read() + const int8View = new Int8Array(result.value.data); + int8View.fill(i); + + frames.push(result.value.data); + senderWriter.write(result.value); + } +}, 'Frames flow correctly using insertable streams'); + +promise_test(async t => { + const caller = new RTCPeerConnection(); + t.add_cleanup(() => caller.close()); + const callee = new RTCPeerConnection(); + t.add_cleanup(() => callee.close()); + const stream = await navigator.mediaDevices.getUserMedia({video:true}); + const videoTrack = stream.getVideoTracks()[0]; + t.add_cleanup(() => videoTrack.stop()); + + await doSignalingHandshake(caller, callee); + + const videoSender = caller.addTrack(videoTrack); + assert_throws_dom("InvalidStateError", () => videoSender.createEncodedVideoStreams()); +}, 'RTCRtpSender.createEncodedVideoStream() throws if not requested in PC configuration'); + +promise_test(async t => { + const caller = new RTCPeerConnection(); + t.add_cleanup(() => caller.close()); + const callee = new RTCPeerConnection(); + t.add_cleanup(() => callee.close()); + const stream = await navigator.mediaDevices.getUserMedia({video:true}); + const videoTrack = stream.getVideoTracks()[0]; + t.add_cleanup(() => videoTrack.stop()); + + const videoSender = caller.addTrack(videoTrack); + const ontrackPromise = new Promise(resolve => { + callee.ontrack = t.step_func(() => { + let receivers = callee.getReceivers(); + let videoReceiver = null; + for (const r of receivers) { + if (r.track.kind == 'video') + videoReceiver = r; + } + assert_true(videoReceiver !== undefined); + assert_throws_dom("InvalidStateError", () => videoReceiver.createEncodedVideoStreams()); + resolve(); + }); + }); + + await doSignalingHandshake(caller, callee); + return ontrackPromise; +}, 'RTCRtpReceiver.createEncodedVideoStream() throws if not requested in PC configuration'); + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/fast/replaced/image-map-cursor-expected.txt b/third_party/blink/web_tests/fast/replaced/image-map-cursor-expected.txt index 7bf223fa..c47f867 100644 --- a/third_party/blink/web_tests/fast/replaced/image-map-cursor-expected.txt +++ b/third_party/blink/web_tests/fast/replaced/image-map-cursor-expected.txt
@@ -1,4 +1,4 @@ -Cursor Info: type=Hand hotSpot=0,0 +Cursor Info: type=Hand PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-restored-breakpoint-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-restored-breakpoint-expected.txt deleted file mode 100644 index 1d8c5c4..0000000 --- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-restored-breakpoint-expected.txt +++ /dev/null
@@ -1,27 +0,0 @@ -Tests breakpoint is restored. -Set different breakpoints and dump them -breakpoint at 5 disabled -breakpoint at 9 -breakpoint at 10 conditional -Reload page and add script again and dump breakpoints -Page reloaded. -breakpoint at 5 disabled -breakpoint at 9 -breakpoint at 10 conditional -Added two more iframes with script with the same url -Show uiSourceCode and dump breakpoints -breakpoint at 9 -breakpoint at 10 conditional -Show uiSourceCode and dump breakpoints -breakpoint at 9 -breakpoint at 10 conditional -Show uiSourceCode and dump breakpoints -breakpoint at 5 disabled -breakpoint at 9 -breakpoint at 10 conditional -Reload page and add script again and dump breakpoints -Page reloaded. -breakpoint at 5 disabled -breakpoint at 9 -breakpoint at 10 conditional -
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-restored-breakpoint.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-restored-breakpoint.js deleted file mode 100644 index fbcde86a5..0000000 --- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-restored-breakpoint.js +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -(async function() { - TestRunner.addResult('Tests breakpoint is restored.'); - await TestRunner.loadModule('sources_test_runner'); - await TestRunner.showPanel('sources'); - - await TestRunner.addScriptTag('resources/a.js'); - - // Pairs of line number plus breakpoint decoration counts. - // We expect line 5, 9 and 10 to have decoration each. - const expectedDecorations = [[5, 1], [9, 1], [10, 1]]; - - let originalSourceFrame = await SourcesTestRunner.showScriptSourcePromise('a.js'); - TestRunner.addResult('Set different breakpoints and dump them'); - await SourcesTestRunner.runActionAndWaitForExactBreakpointDecorations(originalSourceFrame, expectedDecorations, async () => { - await SourcesTestRunner.toggleBreakpoint(originalSourceFrame, 9, false); - await SourcesTestRunner.createNewBreakpoint(originalSourceFrame, 10, 'a === 3', true); - await SourcesTestRunner.createNewBreakpoint(originalSourceFrame, 5, '', false); - }); - - TestRunner.addResult('Reload page and add script again and dump breakpoints'); - await TestRunner.reloadPagePromise(); - await TestRunner.addScriptTag(TestRunner.url('resources/a.js')); - let sourceFrameAfterReload = await SourcesTestRunner.showScriptSourcePromise('a.js'); - await SourcesTestRunner.runActionAndWaitForExactBreakpointDecorations( - sourceFrameAfterReload, expectedDecorations, () => {}, true); - - // TODO(kozyatinskiy): as soon as we have script with the same url in different frames - // everything looks compeltely broken, we should fix it. - TestRunner.addResult('Added two more iframes with script with the same url'); - TestRunner.addIframe(TestRunner.url('resources/frame-with-script.html')); - TestRunner.addIframe(TestRunner.url('resources/frame-with-script.html')); - const uiSourceCodes = await waitForNScriptSources('a.js', 3); - - // The disabled breakpoint at line 5 is currently not included in the iframes that are added. - const expectedDecorationsArray = [[[9, 1], [10, 1]], [[9, 1], [10, 1]], expectedDecorations]; - let index = 0; - for (const uiSourceCode of uiSourceCodes) { - TestRunner.addResult('Show uiSourceCode and dump breakpoints'); - const sourceFrame = await SourcesTestRunner.showUISourceCodePromise(uiSourceCode); - await SourcesTestRunner.runActionAndWaitForExactBreakpointDecorations( - sourceFrame, expectedDecorationsArray[index++], () => {}, true); - } - - TestRunner.addResult('Reload page and add script again and dump breakpoints'); - await TestRunner.reloadPagePromise(); - await TestRunner.addScriptTag(TestRunner.url('resources/a.js')); - sourceFrameAfterReload = await SourcesTestRunner.showScriptSourcePromise('a.js'); - await SourcesTestRunner.runActionAndWaitForExactBreakpointDecorations( - sourceFrameAfterReload, expectedDecorations, () => {}, true); - - TestRunner.completeTest(); - - async function waitForNScriptSources(scriptName, N) { - while (true) { - let uiSourceCodes = UI.panels.sources._workspace.uiSourceCodes(); - uiSourceCodes = uiSourceCodes.filter(uiSourceCode => uiSourceCode.project().type() !== Workspace.projectTypes.Service && uiSourceCode.name() === scriptName); - if (uiSourceCodes.length === N) - return uiSourceCodes; - await TestRunner.addSnifferPromise(Sources.SourcesView.prototype, '_addUISourceCode'); - } - } -})();
diff --git a/third_party/blink/web_tests/http/tests/misc/lock-renderer-for-middle-click-autoscroll.html b/third_party/blink/web_tests/http/tests/misc/lock-renderer-for-middle-click-autoscroll.html index b260ae81..bf9f174c 100644 --- a/third_party/blink/web_tests/http/tests/misc/lock-renderer-for-middle-click-autoscroll.html +++ b/third_party/blink/web_tests/http/tests/misc/lock-renderer-for-middle-click-autoscroll.html
@@ -43,8 +43,7 @@ // Wait for the cursor shape to go back to normal. await waitFor(() => { var cursorInfo = internals.getCurrentCursorInfo(); - return cursorInfo === "type=Pointer hotSpot=0,0" || - cursorInfo === "type=IBeam hotSpot=0,0"; + return cursorInfo === "type=Pointer" || cursorInfo === "type=IBeam"; }); t.step(() => { assert_greater_than(container.scrollTop, 0 , @@ -58,4 +57,4 @@ <iframe id="target-iframe1" src="http://localhost:8080/misc/resources/cross-origin-subframe-for-scrolling.html"> </iframe> -</div> \ No newline at end of file +</div>
diff --git a/third_party/blink/web_tests/http/tests/security/isolatedWorld/bypass-main-world-trusted-types.html b/third_party/blink/web_tests/http/tests/security/isolatedWorld/bypass-main-world-trusted-types.html index d19991a1..efebce2a 100644 --- a/third_party/blink/web_tests/http/tests/security/isolatedWorld/bypass-main-world-trusted-types.html +++ b/third_party/blink/web_tests/http/tests/security/isolatedWorld/bypass-main-world-trusted-types.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> -<meta http-equiv="Content-Security-Policy" content="trusted-types *; require-trusted-types-for 'script';"> +<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script';"> <script> if (window.testRunner) { testRunner.dumpAsText();
diff --git a/third_party/blink/web_tests/shadow-dom/crashes/imperative-api.html b/third_party/blink/web_tests/shadow-dom/crashes/imperative-api.html index 3b44667..f5445793 100644 --- a/third_party/blink/web_tests/shadow-dom/crashes/imperative-api.html +++ b/third_party/blink/web_tests/shadow-dom/crashes/imperative-api.html
@@ -12,7 +12,7 @@ <script> const host = document.querySelector("#host"); const child1 = document.querySelector("#child1"); -const shadow_root = host.attachShadow({ mode: "open", slotting: "manual" }); +const shadow_root = host.attachShadow({ mode: "open", slotAssignment: "manual" }); const slot1 = document.createElement("slot"); const slot2 = document.createElement("slot"); shadow_root.appendChild(slot1);
diff --git a/third_party/blink/web_tests/shadow-dom/imperative-api.html b/third_party/blink/web_tests/shadow-dom/imperative-api.html index 5b900fd..44f15d69 100644 --- a/third_party/blink/web_tests/shadow-dom/imperative-api.html +++ b/third_party/blink/web_tests/shadow-dom/imperative-api.html
@@ -6,27 +6,11 @@ <script src="../resources/testharness.js"></script> <script src="../resources/testharnessreport.js"></script> <script src="resources/shadow-dom.js"></script> -<div id="test1"> - <div id="host"></div> - <div id="host1"></div> - <div id="host2"></div> -</div> -<script> -test(() => { - let n = createTestTree(test1); - assert_not_equals(n.host.attachShadow({ mode: 'open', slotting: 'manual' }), - null, 'slotting manual should work'); - assert_not_equals(n.host1.attachShadow({ mode: 'open', slotting: 'auto' }), - null, 'slotting auto should work'); - assert_throws_js(TypeError, () => { - n.host2.attachShadow({ mode: 'open', slotting: 'exceptional' })}, - 'others should throw exception'); -}, 'attachShadow can take slotting parameter'); </script> <div id="test2"> <div id="host"> - <template id="shadow_root" data-mode="open" data-slotting="manual"> + <template id="shadow_root" data-mode="open" data-slot-assignment="manual"> <slot id="s1"></slot> <slot id="s2"></slot> <slot id="s3"></slot> @@ -37,7 +21,7 @@ </div> <div id="c4"></div> <div id="host4"> - <template id="shadow_root1" data-mode="open" data-slotting="manual"> + <template id="shadow_root1" data-mode="open" data-slot-assignment="manual"> <slot id="s5" name="s5"></slot> </template> </div>
diff --git a/third_party/blink/web_tests/shadow-dom/imperative-apis/custom-detail-summary.js b/third_party/blink/web_tests/shadow-dom/imperative-apis/custom-detail-summary.js index daaee28..835b399 100644 --- a/third_party/blink/web_tests/shadow-dom/imperative-apis/custom-detail-summary.js +++ b/third_party/blink/web_tests/shadow-dom/imperative-apis/custom-detail-summary.js
@@ -11,7 +11,7 @@ customElements.define("my-detail", class extends HTMLElement { constructor() { super(); - this.attachShadow({ mode: "open", slotting: "manual" }); + this.attachShadow({ mode: "open", slotAssignment: "manual" }); } connectedCallback() { const target = this;
diff --git a/third_party/blink/web_tests/shadow-dom/resources/shadow-dom.js b/third_party/blink/web_tests/shadow-dom/resources/shadow-dom.js index c9f2545..7828095 100644 --- a/third_party/blink/web_tests/shadow-dom/resources/shadow-dom.js +++ b/third_party/blink/web_tests/shadow-dom/resources/shadow-dom.js
@@ -76,10 +76,10 @@ if (template.getAttribute('data-mode') === 'v0') { // For legacy Shadow DOM shadowRoot = parent.createShadowRoot(); - } else if (template.getAttribute('data-slotting') === 'manual') { + } else if (template.getAttribute('data-slot-assignment') === 'manual') { shadowRoot = parent.attachShadow({mode: template.getAttribute('data-mode'), - slotting: 'manual'}); + slotAssignment: 'manual'}); } else { shadowRoot = parent.attachShadow({mode: template.getAttribute('data-mode')});
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index cf0eb14..e26fe0b 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -8030,10 +8030,12 @@ getter mode getter pictureInPictureElement getter pointerLockElement + getter slotAssignment getter styleSheets method constructor method elementFromPoint method elementsFromPoint + method getAnimations method getSelection setter adoptedStyleSheets setter fullscreenElement
diff --git a/third_party/blink/web_tests/wpt_internal/portals/portals-cursor.html b/third_party/blink/web_tests/wpt_internal/portals/portals-cursor.html index 27bc173f..2ee7fa6 100644 --- a/third_party/blink/web_tests/wpt_internal/portals/portals-cursor.html +++ b/third_party/blink/web_tests/wpt_internal/portals/portals-cursor.html
@@ -14,7 +14,7 @@ .pointerMove(20, 20, {origin: portal}); actions.send(); await new Promise(r => portal.onpointermove = r); - assert_equals('type=Hand hotSpot=0,0', internals.getCurrentCursorInfo()); + assert_equals('type=Hand', internals.getCurrentCursorInfo()); }, 'test that cursor is updated over portal'); </script> </body>
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath index f791828b..0b1fae7 100644 --- a/tools/android/eclipse/.classpath +++ b/tools/android/eclipse/.classpath
@@ -220,7 +220,6 @@ <classpathentry kind="src" path="content/shell/android/browsertests_apk/src"/> <classpathentry kind="src" path="content/shell/android/java/src"/> <classpathentry kind="src" path="content/shell/android/javatests/src"/> - <classpathentry kind="src" path="content/shell/android/linker_test_apk/src"/> <classpathentry kind="src" path="content/shell/android/shell_apk/src"/> <classpathentry kind="src" path="device/bluetooth/android/java/src"/> <classpathentry kind="src" path="device/bluetooth/test/android/java/src"/>
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py index d206b50b..ff095c6 100755 --- a/tools/clang/scripts/build.py +++ b/tools/clang/scripts/build.py
@@ -475,8 +475,6 @@ '-DCOMPILER_RT_USE_LIBCXX=NO', # Don't run Go bindings tests; PGO makes them confused. '-DLLVM_INCLUDE_GO_TESTS=OFF', - # TODO(b/148147812) Goma client doesn't handle in-process cc1. - '-DCLANG_SPAWN_CC1=ON', ] if args.gcc_toolchain:
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index 5e0643a..f1ea28d 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -41,7 +41,7 @@ # Reverting problematic clang rolls is safe, though. CLANG_REVISION = '9284abd0040afecfd619dbcf1b244a8b533291c9' CLANG_SVN_REVISION = 'n344329' -CLANG_SUB_REVISION = 2 +CLANG_SUB_REVISION = 4 PACKAGE_VERSION = '%s-%s-%s' % (CLANG_SVN_REVISION, CLANG_REVISION[:8], CLANG_SUB_REVISION)
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 40cf6a0..a5e4c8f 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -22560,7 +22560,16 @@ <owner>chrome-signin-team@google.com</owner> <description> The user selected to customize sync from - |chrome://settings/syncSetup/advanced|. + chrome://settings/syncSetup/advanced. + </description> +</action> + +<action name="Sync_NavigateToSyncAdvancedPage"> + <owner>msalama@chromium.org</owner> + <owner>chrome-signin-team@google.com</owner> + <description> + The user has navigated to the sync advanced settings page + chrome://settings/syncSetup/advanced. </description> </action> @@ -22568,8 +22577,8 @@ <owner>msalama@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> <description> - The user has clicked on the history usage row in - |chrome://settings/syncSetup| to open Activity controls page. + The user has clicked on the history usage row in chrome://settings/syncSetup + to open Activity controls page. </description> </action> @@ -22577,8 +22586,7 @@ <owner>msalama@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> <description> - The user selected sync everything from - |chrome://settings/syncSetup/advanced|. + The user selected sync everything from chrome://settings/syncSetup/advanced. </description> </action>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index d1d707e..8a18a48 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -7562,6 +7562,11 @@ <int value="1" label="Unresponsive"/> </enum> +<enum name="BooleanUpdateReceived"> + <int value="0" label="No update"/> + <int value="1" label="Received update"/> +</enum> + <enum name="BooleanUpload"> <int value="0" label="Download"/> <int value="1" label="Upload"/> @@ -8838,6 +8843,10 @@ <int value="32" label="AnnotateStrokeDeviceMouse"/> <int value="33" label="AnnotateStrokeDevicePenFirst"/> <int value="34" label="AnnotateStrokeDevicePen"/> + <int value="35" label="TwoUpViewEnableFirst"/> + <int value="36" label="TwoUpViewEnable"/> + <int value="37" label="TwoUpViewDisableFirst"/> + <int value="38" label="TwoUpViewDisable"/> </enum> <enum name="ChromePDFViewerAnnotationType"> @@ -26780,6 +26789,8 @@ <int value="3184" label="QuicTransport"/> <int value="3185" label="QuicTransportStreamApis"/> <int value="3186" label="QuicTransportDatagramApis"/> + <int value="3187" label="V8Document_GetAnimations_Method"/> + <int value="3188" label="V8ShadowRoot_GetAnimations_Method"/> </enum> <enum name="FeaturePolicyAllowlistType">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 8c7c42b..17d7522 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -8800,16 +8800,13 @@ <!-- Name completed by histogram suffixes name="HotseatTransitionType" --> -<!-- Name completed by histogram suffixes - name="HotseatWidgetElement" --> - <owner>anasalazar@chromium.org</owner> <owner>newcomer@chromium.org</owner> <summary> Tracks the animation smoothness for the bounds animation of the hotseat - widget's elements during transitions of the hotseat to shown, extended, and - hidden hotseat states. Check Ash.HotseatTransition.AnimationSmoothness for - smoothness of the shelf's animating background. + widget during transitions of the hotseat to shown, extended, and hidden + hotseat states. Check Ash.HotseatTransition.AnimationSmoothness for + smoothness of the animating background. </summary> </histogram> @@ -44023,6 +44020,23 @@ </summary> </histogram> +<histogram name="Enterprise.DeviceRemoteCommandInvalidations" + enum="EnterprisePolicyInvalidations" expires_after="2021-03-01"> + <owner>asumaneev@google.com</owner> + <owner>managed-platforms@google.com</owner> + <summary> + Events for counting device remote commands invalidations received with and + without payloads. Invalidations indicate that there is a remote command to + execute. Payloads provide context about the remote commands update, but may + be absent if dropped by the invalidation service. + + Metric is similar to Enterprise.DevicePolicyInvalidations2. Device local + account scope does not exist for remote commands so there is no metric for + remote commands similar to + Enterprise.DeviceLocalAccountPolicyInvalidations2. + </summary> +</histogram> + <histogram name="Enterprise.DeviceSettings.MissingPolicyMitigated" units="BooleanSuccess" expires_after="2020-08-01"> <owner>poromov@chromium.org</owner> @@ -44820,6 +44834,19 @@ </summary> </histogram> +<histogram name="Enterprise.RemoteCommandInvalidationsRegistrationResult" + enum="BooleanSuccess" expires_after="2021-03-01"> + <owner>asumaneev@google.com</owner> + <owner>managed-platforms@google.com</owner> + <summary> + Tracks whether remote commands invalidator registered for corresponding + invalidations. In case of success the invalidator is able to receive + incoming invalidations. + + Metric is similar to Enterprise.PolicyInvalidationsRegistrationResult. + </summary> +</histogram> + <histogram name="Enterprise.ResourceCacheTiming" units="ms" expires_after="2020-03-01"> <obsolete> @@ -45110,6 +45137,20 @@ </summary> </histogram> +<histogram name="Enterprise.UserRemoteCommandInvalidations" + enum="EnterprisePolicyInvalidations" expires_after="2021-03-01"> + <owner>asumaneev@google.com</owner> + <owner>managed-platforms@google.com</owner> + <summary> + Events for counting user remote commands invalidations received with and + without payloads. Invalidations indicate that there is a remote command to + execute. Payloads provide context about the remote commands update, but may + be absent if dropped by the invalidation service. + + Metric is similar to Enterprise.PolicyInvalidations. + </summary> +</histogram> + <histogram name="Enterprise.UserSession.Logins" enum="EnterpriseUserSessionLogins" expires_after="2020-08-30"> <owner>xiyuan@chromium.org</owner> @@ -126717,8 +126758,9 @@ </histogram> <histogram name="Profile.Avatar" enum="ProfileAvatar" - expires_after="2020-03-01"> - <owner>rogerta@chromium.org</owner> + expires_after="2021-03-01"> + <owner>jkrcal@chromium.org</owner> + <owner>droger@chromium.org</owner> <summary>The frequency of selection of each avatar.</summary> </histogram> @@ -127449,9 +127491,9 @@ </histogram> <histogram name="Profile.TimeToOpenUserManagerUpTo1min" units="ms" - expires_after="M82"> + expires_after="2021-03-01"> <owner>msarda@chromium.org</owner> - <owner>tangltom@chromium.org</owner> + <owner>droger@chromium.org</owner> <summary> Time required to open the UserManager, from when it started to show until when its javascript started executing. @@ -135366,6 +135408,30 @@ </summary> </histogram> +<histogram name="SafeBrowsing.V4LocalDatabaseManager.HasReceivedUpdateResponse" + enum="BooleanUpdateReceived" expires_after="2021-03-04"> + <owner>ajuma@chromium.org</owner> + <owner>chrome-safebrowsing-alerts@google.com</owner> + <summary> + Records whether a network response has been received for a request to update + the Safe Browsing local database, since the browser was launched. This will + be logged whenever the database is queried. + </summary> +</histogram> + +<histogram + name="SafeBrowsing.V4LocalDatabaseManager.TimeSinceLastUpdateResponse" + units="ms" expires_after="2021-03-04"> + <owner>ajuma@chromium.org</owner> + <owner>chrome-safebrowsing-alerts@google.com</owner> + <summary> + Records the time since the last network response was received for a request + to udpate the Safe Browsing local database. This will be logged whenever the + database is queried, but only if at least one such network response has been + received since the browser was launched. + </summary> +</histogram> + <histogram name="SafeBrowsing.V4MergeUpdateTime" units="ms" expires_after="2016-10-12"> <obsolete> @@ -187169,14 +187235,6 @@ <affected-histogram name="Ash.NavigationWidget.AnimationSmoothness"/> </histogram_suffixes> -<histogram_suffixes name="HotseatWidgetElement" separator="." - ordering="prefix,2"> - <suffix name="TranslucentBackground" - label="Hotseat widget's translucent background"/> - <suffix name="Widget" label="Hotseat widget"/> - <affected-histogram name="Ash.HotseatWidgetAnimation.AnimationSmoothness"/> -</histogram_suffixes> - <histogram_suffixes name="HstsState" separator="."> <suffix name="HSTSNotEnabled" label="The HSTS is not enabled."/> <suffix name="WithHSTSEnabled" label="The HSTS is enabled."/>
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn index e65edde1..cca5b60c 100644 --- a/ui/android/BUILD.gn +++ b/ui/android/BUILD.gn
@@ -232,6 +232,7 @@ "java/src/org/chromium/ui/base/ActivityWindowAndroid.java", "java/src/org/chromium/ui/base/AndroidPermissionDelegate.java", "java/src/org/chromium/ui/base/AndroidPermissionDelegateWithRequester.java", + "java/src/org/chromium/ui/base/ApplicationViewportInsetSupplier.java", "java/src/org/chromium/ui/base/Clipboard.java", "java/src/org/chromium/ui/base/DeviceFormFactor.java", "java/src/org/chromium/ui/base/EventForwarder.java", @@ -377,6 +378,7 @@ sources = [ "junit/src/org/chromium/ui/AsyncViewProviderTest.java", "junit/src/org/chromium/ui/AsyncViewStubTest.java", + "junit/src/org/chromium/ui/base/ApplicationViewportInsetSupplierTest.java", "junit/src/org/chromium/ui/base/ClipboardTest.java", "junit/src/org/chromium/ui/base/EventOffsetHandlerTest.java", "junit/src/org/chromium/ui/base/LocalizationUtilsTest.java",
diff --git a/ui/android/java/src/org/chromium/ui/base/ApplicationViewportInsetSupplier.java b/ui/android/java/src/org/chromium/ui/base/ApplicationViewportInsetSupplier.java new file mode 100644 index 0000000..5cd35c3 --- /dev/null +++ b/ui/android/java/src/org/chromium/ui/base/ApplicationViewportInsetSupplier.java
@@ -0,0 +1,88 @@ +// Copyright 2020 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.ui.base; + +import androidx.annotation.VisibleForTesting; + +import org.chromium.base.Callback; +import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.ObservableSupplierImpl; + +import java.util.HashSet; +import java.util.Set; + +/** + * A class responsible for managing multiple users of window viewport insets. The class that + * actually updates the viewport insets listens to this class via {@link #addObserver(Callback)}. + * Other features can also listen to this class to know if something is obscuring part of the + * screen. Features that wish to update the viewport's insets can attach an inset supplier via + * {@link #addSupplier(ObservableSupplier)}. This class will use the largest inset value to + * adjust the viewport inset. + * + * In general: + * - Features that want to modify the inset should pass around the + * {@link ApplicationViewportInsetSupplier} object. + * - Features only interested in what the current inset is should pass around an + * {@link ObservableSupplier<Integer>} object. + */ +public class ApplicationViewportInsetSupplier extends ObservableSupplierImpl<Integer> { + /** The list of inset providers that this class manages. */ + private final Set<ObservableSupplier<Integer>> mInsetSuppliers = new HashSet<>(); + + /** The observer that gets attached to all inset providers. */ + private final Callback<Integer> mInsetSupplierObserver = (inset) -> computeInset(); + + /** Default constructor. */ + ApplicationViewportInsetSupplier() { + super(); + // Make sure this is initialized to 0 since "Integer" is an object and would be null + // otherwise. + super.set(0); + } + + @VisibleForTesting + public static ApplicationViewportInsetSupplier createForTests() { + return new ApplicationViewportInsetSupplier(); + } + + /** Clean up observers and suppliers. */ + public void destroy() { + for (ObservableSupplier<Integer> os : mInsetSuppliers) { + os.removeObserver(mInsetSupplierObserver); + } + mInsetSuppliers.clear(); + } + + /** Compute the new inset based on the current registered providers. */ + private void computeInset() { + int currentInset = 0; + for (ObservableSupplier<Integer> os : mInsetSuppliers) { + // Similarly to the constructor, check that the Integer object isn't null as the + // supplier may not yet have supplied the initial value. + currentInset = Math.max(currentInset, os.get() == null ? 0 : os.get()); + } + + super.set(currentInset); + } + + @Override + public void set(Integer value) { + throw new IllegalStateException( + "#set(...) should not be called directly on ApplicationViewportInsetSupplier."); + } + + /** @param insetSupplier A supplier of bottom insets to be added. */ + public void addSupplier(ObservableSupplier<Integer> insetSupplier) { + mInsetSuppliers.add(insetSupplier); + insetSupplier.addObserver(mInsetSupplierObserver); + } + + /** @param insetSupplier A supplier of bottom insets to be removed. */ + public void removeSupplier(ObservableSupplier<Integer> insetSupplier) { + mInsetSuppliers.remove(insetSupplier); + insetSupplier.removeObserver(mInsetSupplierObserver); + computeInset(); + } +}
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java index 99374ad..db08c9f 100644 --- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java +++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -121,6 +121,10 @@ // System accessibility service. private final AccessibilityManager mAccessibilityManager; + /** A mechanism for observing and updating the application window's bottom inset. */ + private ApplicationViewportInsetSupplier mApplicationBottomInsetProvider = + new ApplicationViewportInsetSupplier(); + // Whether touch exploration is enabled. private boolean mIsTouchExplorationEnabled; @@ -653,6 +657,7 @@ } TouchlessEventHandler.removeCursorObserver(mCursorObserver); + mApplicationBottomInsetProvider.destroy(); } /** @@ -733,6 +738,11 @@ return mKeyboardVisibilityDelegate; } + /** @return A mechanism for updating and observing the bottom inset of the browser window. */ + public ApplicationViewportInsetSupplier getApplicationBottomInsetProvider() { + return mApplicationBottomInsetProvider; + } + @VisibleForTesting public void setKeyboardDelegate(KeyboardVisibilityDelegate keyboardDelegate) { mKeyboardVisibilityDelegate = keyboardDelegate;
diff --git a/ui/android/junit/src/org/chromium/ui/base/ApplicationViewportInsetSupplierTest.java b/ui/android/junit/src/org/chromium/ui/base/ApplicationViewportInsetSupplierTest.java new file mode 100644 index 0000000..e2584ae --- /dev/null +++ b/ui/android/junit/src/org/chromium/ui/base/ApplicationViewportInsetSupplierTest.java
@@ -0,0 +1,133 @@ +// Copyright 2020 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.ui.base; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.Callback; +import org.chromium.base.supplier.ObservableSupplierImpl; +import org.chromium.base.test.BaseRobolectricTestRunner; + +/** Unit tests for the ApplicationViewportInsetSupplier. */ +@RunWith(BaseRobolectricTestRunner.class) +public class ApplicationViewportInsetSupplierTest { + /** A callback with the ability to get the last value pushed to it. */ + private static class CapturingCallback<T> implements Callback<T> { + private T mValue; + + @Override + public void onResult(T result) { + mValue = result; + } + + public T getCapturedValue() { + return mValue; + } + } + + private ApplicationViewportInsetSupplier mWindowApplicationInsetSupplier; + private ObservableSupplierImpl<Integer> mFeatureInsetSupplier; + private CapturingCallback<Integer> mWindowInsetObserver; + + @Before + public void setUp() { + mWindowApplicationInsetSupplier = new ApplicationViewportInsetSupplier(); + mFeatureInsetSupplier = new ObservableSupplierImpl<>(); + mWindowInsetObserver = new CapturingCallback<>(); + + mWindowApplicationInsetSupplier.addSupplier(mFeatureInsetSupplier); + mWindowApplicationInsetSupplier.addObserver(mWindowInsetObserver); + } + + @Test + public void testSupplierDidNotSetValue() { + assertEquals("Observed value from supplier is incorrect.", (Integer) 0, + mWindowApplicationInsetSupplier.get()); + } + + @Test + public void testSupplierTriggersObserver() { + mFeatureInsetSupplier.set(5); + assertEquals("Observed value from supplier is incorrect.", (Integer) 5, + mWindowInsetObserver.getCapturedValue()); + } + + @Test + public void testSupplierTriggersObserver_multipleSuppliers_2() { + ObservableSupplierImpl<Integer> secondSupplier = new ObservableSupplierImpl<>(); + mWindowApplicationInsetSupplier.addSupplier(secondSupplier); + + mFeatureInsetSupplier.set(5); + secondSupplier.set(10); + + assertEquals("Observed value should be the max of the two supplied.", (Integer) 10, + mWindowInsetObserver.getCapturedValue()); + } + + @Test + public void testSupplierTriggersObserver_multipleSuppliers_3() { + ObservableSupplierImpl<Integer> secondSupplier = new ObservableSupplierImpl<>(); + mWindowApplicationInsetSupplier.addSupplier(secondSupplier); + + ObservableSupplierImpl<Integer> thirdSupplier = new ObservableSupplierImpl<>(); + mWindowApplicationInsetSupplier.addSupplier(thirdSupplier); + + mFeatureInsetSupplier.set(5); + secondSupplier.set(20); + thirdSupplier.set(10); + + assertEquals("Observed value should be the max of the three supplied.", (Integer) 20, + mWindowInsetObserver.getCapturedValue()); + } + + @Test + public void testSupplierTriggersObserver_setBeforeAdded() { + ObservableSupplierImpl<Integer> supplier = new ObservableSupplierImpl<>(); + supplier.set(20); + + mWindowApplicationInsetSupplier.addSupplier(supplier); + + assertEquals("The observer should have been triggered after the supplier was added.", + (Integer) 20, mWindowInsetObserver.getCapturedValue()); + } + + @Test + public void testSupplierRemoveTriggersEvent() { + ObservableSupplierImpl<Integer> secondSupplier = new ObservableSupplierImpl<>(); + mWindowApplicationInsetSupplier.addSupplier(secondSupplier); + + ObservableSupplierImpl<Integer> thirdSupplier = new ObservableSupplierImpl<>(); + mWindowApplicationInsetSupplier.addSupplier(thirdSupplier); + + mFeatureInsetSupplier.set(5); + secondSupplier.set(20); + thirdSupplier.set(10); + + assertEquals("Observed value should be the max of the three supplied.", (Integer) 20, + mWindowInsetObserver.getCapturedValue()); + + mWindowApplicationInsetSupplier.removeSupplier(secondSupplier); + + assertEquals("Observed value should be the max of the two remaining.", (Integer) 10, + mWindowInsetObserver.getCapturedValue()); + } + + @Test + public void testAllSuppliersRemoved() { + mFeatureInsetSupplier.set(5); + + assertEquals("Observed value from supplier is incorrect.", (Integer) 5, + mWindowInsetObserver.getCapturedValue()); + + mWindowApplicationInsetSupplier.removeSupplier(mFeatureInsetSupplier); + + assertEquals("Observed value should be 0 with no suppliers attached.", (Integer) 0, + mWindowInsetObserver.getCapturedValue()); + } +}
diff --git a/ui/events/gesture_detection/gesture_detector.cc b/ui/events/gesture_detection/gesture_detector.cc index 7523ad0e..5ee0e7c 100644 --- a/ui/events/gesture_detection/gesture_detector.cc +++ b/ui/events/gesture_detection/gesture_detector.cc
@@ -11,6 +11,7 @@ #include "base/numerics/ranges.h" #include "base/timer/timer.h" #include "build/build_config.h" +#include "ui/events/event_constants.h" #include "ui/events/gesture_detection/gesture_listeners.h" #include "ui/events/gesture_detection/motion_event.h" #include "ui/gfx/geometry/angle_conversions.h" @@ -51,6 +52,11 @@ two_finger_tap_max_separation(300), two_finger_tap_timeout(base::TimeDelta::FromMilliseconds(700)), single_tap_repeat_interval(1), +#if defined(OS_CHROMEOS) + stylus_button_accelerated_longpress_enabled(true), +#else + stylus_button_accelerated_longpress_enabled(false), +#endif velocity_tracker_strategy(VelocityTracker::Strategy::STRATEGY_DEFAULT) { } @@ -135,6 +141,7 @@ last_focus_y_(0), down_focus_x_(0), down_focus_y_(0), + stylus_button_accelerated_longpress_enabled_(false), longpress_enabled_(true), showpress_enabled_(true), swipe_enabled_(false), @@ -333,6 +340,11 @@ last_focus_y_ = focus_y; } + if (stylus_button_accelerated_longpress_enabled_ && + (ev.GetFlags() & ui::EF_LEFT_MOUSE_BUTTON)) { + OnStylusButtonPress(ev); + } + if (!two_finger_tap_allowed_for_gesture_) break; @@ -458,6 +470,8 @@ DCHECK_GE(config.single_tap_repeat_interval, 1); single_tap_repeat_interval_ = config.single_tap_repeat_interval; + stylus_button_accelerated_longpress_enabled_ = + config.stylus_button_accelerated_longpress_enabled; } void GestureDetector::OnShowPressTimeout() { @@ -481,6 +495,20 @@ } } +void GestureDetector::OnStylusButtonPress(const MotionEvent& ev) { + if (!timeout_handler_->HasTimeout(LONG_PRESS)) + return; + timeout_handler_->StopTimeout(TAP); + timeout_handler_->StopTimeout(SHOW_PRESS); + timeout_handler_->StopTimeout(LONG_PRESS); + defer_confirm_single_tap_ = false; + // This will generate a ET_GESTURE_LONG_PRESS event with EF_LEFT_MOUSE_BUTTON, + // which is consumed by MetalayerMode if that feature is enabled, because + // MetalayerMode is also activated by a stylus button press and has precedence + // over this press acceleration feature. + listener_->OnLongPress(ev); +} + void GestureDetector::Cancel() { // Stop waiting for a second tap and send a GESTURE_TAP_CANCEL to keep the // gesture stream valid.
diff --git a/ui/events/gesture_detection/gesture_detector.h b/ui/events/gesture_detection/gesture_detector.h index 761bc5a..e525277b 100644 --- a/ui/events/gesture_detection/gesture_detector.h +++ b/ui/events/gesture_detection/gesture_detector.h
@@ -77,6 +77,10 @@ // count will always be 1. int single_tap_repeat_interval; + // Whether a longpress should be generated immediately when a stylus button + // is pressed, given that the longpress timeout is still active. + bool stylus_button_accelerated_longpress_enabled; + VelocityTracker::Strategy velocity_tracker_strategy; }; @@ -112,6 +116,7 @@ void OnShowPressTimeout(); void OnLongPressTimeout(); void OnTapTimeout(); + void OnStylusButtonPress(const MotionEvent& ev); void Cancel(); void CancelTaps(); bool IsRepeatedTap(const MotionEvent& first_down, @@ -172,6 +177,7 @@ float down_focus_x_; float down_focus_y_; + bool stylus_button_accelerated_longpress_enabled_; bool longpress_enabled_; bool showpress_enabled_; bool swipe_enabled_;
diff --git a/ui/events/gesture_detection/gesture_provider_unittest.cc b/ui/events/gesture_detection/gesture_provider_unittest.cc index 5386ab3..9c0b37b 100644 --- a/ui/events/gesture_detection/gesture_provider_unittest.cc +++ b/ui/events/gesture_detection/gesture_provider_unittest.cc
@@ -298,6 +298,13 @@ SetUpWithConfig(config); } + void SetStylusButtonAcceleratedLongPress(bool enabled) { + GestureProvider::Config config = GetDefaultConfig(); + config.gesture_detector_config.stylus_button_accelerated_longpress_enabled = + enabled; + SetUpWithConfig(config); + } + bool HasDownEvent() const { return gesture_provider_->current_down_event(); } protected: @@ -1249,6 +1256,36 @@ EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP)); } +TEST_F(GestureProviderTest, StylusButtonCausesLongPress) { + SetStylusButtonAcceleratedLongPress(true); + base::TimeTicks event_time = base::TimeTicks::Now(); + + MockMotionEvent event = + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); + EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); + + event = ObtainMotionEvent(event_time + kOneMicrosecond, + MotionEvent::Action::MOVE); + event.set_flags(EF_LEFT_MOUSE_BUTTON); + EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); + EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType()); +} + +TEST_F(GestureProviderTest, DisabledStylusButtonDoesNotCauseLongPress) { + SetStylusButtonAcceleratedLongPress(false); + base::TimeTicks event_time = base::TimeTicks::Now(); + + MockMotionEvent event = + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); + EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); + + event = ObtainMotionEvent(event_time + kOneMicrosecond, + MotionEvent::Action::MOVE); + event.set_flags(EF_LEFT_MOUSE_BUTTON); + EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); + EXPECT_NE(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType()); +} + TEST_F(GestureProviderTest, NoGestureLongPressDuringDoubleTap) { base::TimeTicks event_time = base::TimeTicks::Now(); int motion_event_id = 6;
diff --git a/ui/file_manager/integration_tests/file_manager/search.js b/ui/file_manager/integration_tests/file_manager/search.js index 76976d4..dd2b0d8 100644 --- a/ui/file_manager/integration_tests/file_manager/search.js +++ b/ui/file_manager/integration_tests/file_manager/search.js
@@ -163,4 +163,52 @@ await remoteCall.waitForElement(appId, ['#search-box cr-input']); chrome.test.assertEq('false', textInputElement.attributes['aria-disabled']); }; + + /** + * Tests that the search box collapses when empty and Tab out of the box. + */ + testcase.searchHidingViaTab = async () => { + const entry = ENTRIES.hello; + + // Open Files app on Downloads. + const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, [entry], []); + + // Measure the width of the search box when it's collapsed. + const collapsedSearchBox = await remoteCall.waitForElementStyles( + appId, '#search-wrapper', ['width']); + + // Click the toolbar search button. + chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( + 'fakeEvent', appId, ['#search-button', 'click'])); + + // Wait search box to be expanded. + const caller = getCaller(); + await repeatUntil(async () => { + const element = await remoteCall.waitForElementStyles( + appId, '#search-wrapper', ['width']); + if (collapsedSearchBox.renderedWidth > element.renderedWidth) { + return pending(caller, 'Waiting search box to expand'); + } + }); + + // Verify the search input has focus. + const input = + await remoteCall.callRemoteTestUtil('deepGetActiveElement', appId, []); + chrome.test.assertEq(input.attributes['id'], 'input'); + chrome.test.assertEq(input.attributes['aria-label'], 'Search'); + + // Send Tab key to focus the next element. + const result = await sendTestMessage({name: 'dispatchTabKey'}); + chrome.test.assertEq( + result, 'tabKeyDispatched', 'Tab key dispatch failure'); + + // Check: the search box should collapse. + await repeatUntil(async () => { + const element = await remoteCall.waitForElementStyles( + appId, '#search-wrapper', ['width']); + if (collapsedSearchBox.renderedWidth < element.renderedWidth) { + return pending(caller, 'Waiting search box to collapse'); + } + }); + }; })();
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc index 46eb655..cfb59c05 100644 --- a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc +++ b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
@@ -104,6 +104,8 @@ void OnWidgetDestroying(Widget* widget) override { auto iter = std::find(widgets_.begin(), widgets_.end(), widget); + // Since |widget| is about to be destroyed, there is no point in removing + // |this| from its list of observers. if (iter != widgets_.end()) widgets_.erase(iter); }
diff --git a/ui/views/controls/menu/menu_runner_cocoa_unittest.mm b/ui/views/controls/menu/menu_runner_cocoa_unittest.mm index 5193079..3213086 100644 --- a/ui/views/controls/menu/menu_runner_cocoa_unittest.mm +++ b/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
@@ -334,7 +334,8 @@ // Tests a potential lifetime issue using the Cocoa MenuController, which has a // weak reference to the model. -TEST_P(MenuRunnerCocoaTest, RunMenuAndDeleteThenSelectItem) { +// Disabled: crbug.com/1060063 +TEST_P(MenuRunnerCocoaTest, DISABLED_RunMenuAndDeleteThenSelectItem) { RunMenu( base::BindOnce(&MenuRunnerCocoaTest::ModelDeleteThenSelectItemCallback, base::Unretained(this))); @@ -343,7 +344,8 @@ // Ensure a menu can be safely released immediately after a call to Cancel() in // the same run loop iteration. -TEST_P(MenuRunnerCocoaTest, DestroyAfterCanceling) { +// Disabled: crbug.com/1060063 +TEST_P(MenuRunnerCocoaTest, DISABLED_DestroyAfterCanceling) { RunMenu(base::BindOnce(&MenuRunnerCocoaTest::MenuCancelAndDeleteCallback, base::Unretained(this))); @@ -380,7 +382,8 @@ } // Tests anchoring of the menus used for toolkit-views Comboboxes. -TEST_P(MenuRunnerCocoaTest, ComboboxAnchoring) { +// Disabled: crbug.com/1060063 +TEST_P(MenuRunnerCocoaTest, DISABLED_ComboboxAnchoring) { // Combobox at 20,10 in the Widget. const gfx::Rect combobox_rect(20, 10, 80, 50);
diff --git a/ui/views/layout/flex_layout_types.cc b/ui/views/layout/flex_layout_types.cc index 2d25fd54..ed32ed8c 100644 --- a/ui/views/layout/flex_layout_types.cc +++ b/ui/views/layout/flex_layout_types.cc
@@ -25,6 +25,12 @@ int minimum_size, int preferred_size, int available_size) { + // A view may (mistakenly) report a minimum size larger than its preferred + // size. While in principle this shouldn't happen, by the time we've gotten + // here it's better to simply make sure the minimum and preferred don't + // cross. + minimum_size = std::min(minimum_size, preferred_size); + if (available_size < minimum_size) { switch (minimum_size_rule) { case MinimumFlexSizeRule::kScaleToZero: