diff --git a/DEPS b/DEPS index 3c539105..e1b89dd2 100644 --- a/DEPS +++ b/DEPS
@@ -105,11 +105,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'ba651682ae856b40f5b79187025d13faab844183', + 'skia_revision': '9b7bfd09106fa136721b229265f5d5eb2b397e57', # 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': '9f7f390a79ded307b7050dadf1e939c5e901e21d', + 'v8_revision': '9c646035e144006c5ede9e537e66aeedd117c690', # 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. @@ -181,7 +181,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'feed_revision': 'e291161061d18d222bc1b546225fe0567386cbf1', + 'feed_revision': '2cefe05b77f7039db95a63804edf284e68055dda', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_build-tools_version # and whatever else without interference from each other. @@ -595,7 +595,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '39a66e9fc8df234f9ce48c7b7a431fc5e59aad00', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'bef4a89b1e9fb152a3a1e44285772500016f7a68', 'condition': 'checkout_linux', }, @@ -813,7 +813,7 @@ Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'd7ed8e2f3f35ce9a3aafdfdc48745ceab66e7229', 'src/third_party/libaom/source/libaom': { - 'url': Var('aomedia_git') + '/aom.git' + '@' + 'f866f5ebb34b22afc2244789dc8551b0c8d99a13', + 'url': Var('aomedia_git') + '/aom.git' + '@' + 'a5078bf8d0e7c01eab670cfc1cfe7b9fb065e931', 'condition': 'checkout_libaom', }, @@ -853,7 +853,7 @@ }, 'src/third_party/libvpx/source/libvpx': - Var('chromium_git') + '/webm/libvpx.git' + '@' + '2beb5c9f91e7166c2c9d01c94bf84767815121e4', + Var('chromium_git') + '/webm/libvpx.git' + '@' + 'ecc31d28781c490f5fb18a3e6873692a1b8e6cea', 'src/third_party/libwebm/source': Var('chromium_git') + '/webm/libwebm.git' + '@' + '01c1d1d76f139345c442bfc8e61b4e1cba809059', @@ -1106,7 +1106,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6d2f3f4cb8bac1f7c4a945c73d07a33df74f22f9', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '3a7423909164538a047a0bd93ae0dfbb575ba2dd', + Var('webrtc_git') + '/src.git' + '@' + 'ab09039d2ab6d66d3a57c6caa626034d9effb62e', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1137,7 +1137,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3c569553009589659019b3909c270727d450c02a', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@be97d2b8d9afd08cf06a9b33b42d42c6ace4700a', 'condition': 'checkout_src_internal', },
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index cca5da8..7539ed8 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -71,9 +71,9 @@ "wm/mru_window_tracker.h", "wm/overview/window_selector_controller.h", "wm/splitview/split_view_controller.h", - "wm/tablet_mode/tablet_mode_app_window_drag_controller.h", "wm/tablet_mode/tablet_mode_controller.h", "wm/tablet_mode/tablet_mode_observer.h", + "wm/tablet_mode/tablet_mode_window_drag_delegate.h", "wm/window_finder.h", "wm/window_positioner.h", "wm/window_positioning_utils.h", @@ -1246,7 +1246,6 @@ "wm/video_detector.h", "wm/widget_finder.cc", "wm/widget_finder.h", - "wm/window_animation_types.h", "wm/window_animations.cc", "wm/window_animations.h", "wm/window_cycle_controller.cc",
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc index 7ac04ef0..2cbc31de 100644 --- a/ash/app_list/app_list_controller_impl.cc +++ b/ash/app_list/app_list_controller_impl.cc
@@ -724,7 +724,7 @@ case ui::ET_SCROLL_FLING_START: case ui::ET_GESTURE_SCROLL_BEGIN: return home_launcher_gesture_handler_->OnPressEvent( - HomeLauncherGestureHandler::Mode::kSwipeDownToHide); + HomeLauncherGestureHandler::Mode::kSlideDownToHide, screen_location); case ui::ET_GESTURE_SCROLL_UPDATE: return home_launcher_gesture_handler_->OnScrollEvent(screen_location); case ui::ET_GESTURE_END: @@ -742,7 +742,7 @@ return false; return home_launcher_gesture_handler_->mode() == - HomeLauncherGestureHandler::Mode::kSwipeUpToShow; + HomeLauncherGestureHandler::Mode::kSlideUpToShow; } ws::WindowService* AppListControllerImpl::GetWindowService() {
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc index b1bac41..12f4940 100644 --- a/ash/app_list/app_list_presenter_delegate_unittest.cc +++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -1135,7 +1135,7 @@ ->shelf_controller() ->model() ->GetShelfItemDelegate(ShelfID(kAppListId)) - ->ItemSelected(std::move(event), display::kInvalidDisplayId, + ->ItemSelected(std::move(event), GetPrimaryDisplayId(), ash::LAUNCH_FROM_UNKNOWN, base::DoNothing()); GetAppListTestHelper()->WaitUntilIdle(); }
diff --git a/ash/app_list/home_launcher_gesture_handler.cc b/ash/app_list/home_launcher_gesture_handler.cc index 47b3fb0..537448b6 100644 --- a/ash/app_list/home_launcher_gesture_handler.cc +++ b/ash/app_list/home_launcher_gesture_handler.cc
@@ -16,6 +16,7 @@ #include "ash/wm/splitview/split_view_divider.h" #include "ash/wm/window_state.h" #include "ash/wm/window_transient_descendant_iterator.h" +#include "ash/wm/window_util.h" #include "ash/wm/workspace/backdrop_controller.h" #include "ash/wm/workspace/workspace_layout_manager.h" #include "ash/wm/workspace_controller.h" @@ -45,19 +46,20 @@ // Checks if |window| can be hidden or shown with a gesture. bool CanProcessWindow(aura::Window* window, HomeLauncherGestureHandler::Mode mode) { - DCHECK(window); + if (!window) + return false; // Window should not be fullscreen as we do not allow swiping up when auto // hide for shelf. DCHECK(!wm::GetWindowState(window)->IsFullscreen()); if (!window->IsVisible() && - mode == HomeLauncherGestureHandler::Mode::kSwipeUpToShow) { + mode == HomeLauncherGestureHandler::Mode::kSlideUpToShow) { return false; } if (window->IsVisible() && - mode == HomeLauncherGestureHandler::Mode::kSwipeDownToHide) { + mode == HomeLauncherGestureHandler::Mode::kSlideDownToHide) { return false; } @@ -110,10 +112,8 @@ // Given a |location_in_screen|, find out where it lies as a ratio in the // work area, where the top of the work area is 0.f and the bottom is 1.f. -double GetHeightInWorkAreaAsRatio(const gfx::Point& location_in_screen) { - gfx::Rect work_area = display::Screen::GetScreen() - ->GetDisplayNearestPoint(location_in_screen) - .work_area(); +double GetHeightInWorkAreaAsRatio(const gfx::Point& location_in_screen, + const gfx::Rect& work_area) { int clamped_y = base::ClampToRange(location_in_screen.y(), work_area.y(), work_area.bottom()); double ratio = @@ -121,8 +121,9 @@ return 1.0 - ratio; } -bool IsLastEventInTopHalf(const gfx::Point& location_in_screen) { - return GetHeightInWorkAreaAsRatio(location_in_screen) > 0.5; +bool IsLastEventInTopHalf(const gfx::Point& location_in_screen, + const gfx::Rect& work_area) { + return GetHeightInWorkAreaAsRatio(location_in_screen, work_area) > 0.5; } // Returns the window of the widget which contains the workspace backdrop. May @@ -184,50 +185,438 @@ StopObservingImplicitAnimations(); } -bool HomeLauncherGestureHandler::OnPressEvent(Mode mode) { +bool HomeLauncherGestureHandler::OnPressEvent(Mode mode, + const gfx::Point& location) { // Do not start a new session if a window is currently being processed. - if (last_event_location_) + if (!IsIdle()) return false; + display_ = display::Screen::GetScreen()->GetDisplayNearestPoint(location); + if (!display_.is_valid()) + return false; + + if (!SetUpWindows(mode, nullptr /* window */)) + return false; + + mode_ = mode; + last_event_location_ = base::make_optional(location); + + UpdateWindows(0.0, /*animate=*/false); + return true; +} + +bool HomeLauncherGestureHandler::OnScrollEvent(const gfx::Point& location) { + if (!IsDragInProgress()) + return false; + + last_event_location_ = base::make_optional(location); + DCHECK(display_.is_valid()); + UpdateWindows(GetHeightInWorkAreaAsRatio(location, display_.work_area()), + /*animate=*/false); + return true; +} + +bool HomeLauncherGestureHandler::OnReleaseEvent(const gfx::Point& location) { + if (!IsDragInProgress()) + return false; + + last_event_location_ = base::make_optional(location); + AnimateToFinalState(); + return true; +} + +void HomeLauncherGestureHandler::Cancel() { + if (!IsDragInProgress()) + return; + + AnimateToFinalState(); + return; +} + +bool HomeLauncherGestureHandler::ShowHomeLauncher( + const display::Display& display) { + if (!IsIdle()) + return false; + + if (!display.is_valid()) + return false; + + if (!SetUpWindows(Mode::kSlideUpToShow, nullptr /* window */)) + return false; + + display_ = display; + mode_ = Mode::kSlideUpToShow; + + UpdateWindows(0.0, /*animate=*/false); + AnimateToFinalState(); + return true; +} + +bool HomeLauncherGestureHandler::HideHomeLauncherForWindow( + const display::Display& display, + aura::Window* window) { + if (!IsIdle()) + return false; + + if (!display.is_valid()) + return false; + + if (!SetUpWindows(Mode::kSlideDownToHide, window)) + return false; + + display_ = display; + mode_ = Mode::kSlideDownToHide; + + UpdateWindows(1.0, /*animate=*/false); + AnimateToFinalState(); + return true; +} + +void HomeLauncherGestureHandler::OnWindowDestroying(aura::Window* window) { + if (window == window_) { + for (auto* hidden_window : hidden_windows_) + hidden_window->Show(); + + RemoveObserversAndStopTracking(); + return; + } + + if (window == window2_) { + DCHECK(window_); + window->RemoveObserver(this); + window2_ = nullptr; + return; + } + + if (transient_descendants_values_.find(window) != + transient_descendants_values_.end()) { + window->RemoveObserver(this); + transient_descendants_values_.erase(window); + return; + } + + if (transient_descendants_values2_.find(window) != + transient_descendants_values2_.end()) { + window->RemoveObserver(this); + transient_descendants_values2_.erase(window); + return; + } + + DCHECK(base::ContainsValue(hidden_windows_, window)); + window->RemoveObserver(this); + hidden_windows_.erase( + std::find(hidden_windows_.begin(), hidden_windows_.end(), window)); +} + +void HomeLauncherGestureHandler::OnTabletModeEnded() { + if (IsIdle()) + return; + + // When leaving tablet mode advance to the end of the in progress scroll + // session or animation. + StopObservingImplicitAnimations(); + if (window_) + window_->layer()->GetAnimator()->StopAnimating(); + if (window2_) + window2_->layer()->GetAnimator()->StopAnimating(); + for (const auto& descendant : transient_descendants_values_) + descendant.first->layer()->GetAnimator()->StopAnimating(); + for (const auto& descendant : transient_descendants_values2_) + descendant.first->layer()->GetAnimator()->StopAnimating(); + UpdateWindows(IsFinalStateShow() ? 1.0 : 0.0, + /*animate=*/false); + OnImplicitAnimationsCompleted(); +} + +void HomeLauncherGestureHandler::OnImplicitAnimationsCompleted() { + float app_list_opacity = 1.f; + const bool is_final_state_show = IsFinalStateShow(); + if (Shell::Get()->window_selector_controller()->IsSelecting()) { + if (is_final_state_show) { + // Exit overview if event is released on the top half. This will also end + // splitview if it is active as SplitViewController observes overview mode + // ends. + Shell::Get()->window_selector_controller()->ToggleOverview( + WindowSelector::EnterExitOverviewType::kSwipeFromShelf); + } else { + app_list_opacity = 0.f; + } + } + + // Return the app list to its original opacity and transform without + // animation. + DCHECK(display_.is_valid()); + app_list_controller_->presenter()->UpdateYPositionAndOpacityForHomeLauncher( + display_.work_area().y(), app_list_opacity, base::NullCallback()); + + if (!window_) { + RemoveObserversAndStopTracking(); + return; + } + + // Explicitly exit split view if two windows are snapped. + if (is_final_state_show && Shell::Get()->split_view_controller()->state() == + SplitViewController::BOTH_SNAPPED) { + Shell::Get()->split_view_controller()->EndSplitView(); + } + + window_->SetTransform(window_values_.initial_transform); + window_->layer()->SetOpacity(window_values_.initial_opacity); + if (window2_) { + window2_->SetTransform(window_values2_.initial_transform); + window2_->layer()->SetOpacity(window_values2_.initial_opacity); + } + + if (is_final_state_show) { + ScopedAnimationDisabler disable(window_); + wm::GetWindowState(window_)->Minimize(); + + if (window2_) { + ScopedAnimationDisabler disable(window2_); + wm::GetWindowState(window2_)->Minimize(); + } + + // Minimize the hidden windows so they can be used normally with alt+tab + // and overview. Minimize in reverse order to preserve mru ordering. + std::reverse(hidden_windows_.begin(), hidden_windows_.end()); + for (auto* window : hidden_windows_) { + ScopedAnimationDisabler disable(window); + wm::GetWindowState(window)->Minimize(); + } + } else { + // Reshow all windows previously hidden. + for (auto* window : hidden_windows_) { + ScopedAnimationDisabler disable(window); + window->Show(); + } + } + + // Update the backdrop last as the backdrop controller listens for some state + // changes like minimizing above which may also alter the backdrop. + aura::Window* backdrop_window = GetBackdropWindow(window_); + if (backdrop_window) { + backdrop_window->SetTransform(gfx::Transform()); + backdrop_window->layer()->SetOpacity(1.f); + } + + RemoveObserversAndStopTracking(); +} + +void HomeLauncherGestureHandler::AnimateToFinalState() { + const bool is_final_state_show = IsFinalStateShow(); + UpdateWindows(is_final_state_show ? 1.0 : 0.0, /*animate=*/true); + + if (!is_final_state_show && mode_ == Mode::kSlideDownToHide) { + base::RecordAction( + base::UserMetricsAction("AppList_HomeLauncherToMRUWindow")); + } else if (is_final_state_show && mode_ == Mode::kSlideUpToShow) { + base::RecordAction( + base::UserMetricsAction("AppList_CurrentWindowToHomeLauncher")); + } +} + +void HomeLauncherGestureHandler::UpdateSettings( + ui::ScopedLayerAnimationSettings* settings, + bool observe) { + // TODO(sammiequon): The animation should change based on the distance to the + // end. + settings->SetTransitionDuration(kAnimationDurationMs); + settings->SetTweenType(gfx::Tween::LINEAR); + settings->SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + + if (observe) + settings->AddObserver(this); +} + +void HomeLauncherGestureHandler::UpdateWindows(double progress, bool animate) { + // Update full screen applist. + DCHECK(display_.is_valid()); + const gfx::Rect work_area = display_.work_area(); + const int y_position = + gfx::Tween::IntValueBetween(progress, work_area.bottom(), work_area.y()); + const float opacity = gfx::Tween::FloatValueBetween(progress, 0.f, 1.f); + app_list_controller_->presenter()->UpdateYPositionAndOpacityForHomeLauncher( + y_position, opacity, + animate ? base::BindRepeating(&HomeLauncherGestureHandler::UpdateSettings, + base::Unretained(this)) + : base::NullCallback()); + + // Update the overview grid if needed. + WindowSelectorController* controller = + Shell::Get()->window_selector_controller(); + if (controller->IsSelecting()) { + DCHECK_EQ(mode_, Mode::kSlideUpToShow); + controller->window_selector()->UpdateGridAtLocationYPositionAndOpacity( + display_.id(), y_position - work_area.height(), 1.f - opacity, + work_area, + animate + ? base::BindRepeating(&HomeLauncherGestureHandler::UpdateSettings, + base::Unretained(this)) + : base::NullCallback()); + } + + if (!window_) + return; + + // Helper to update a single windows opacity and transform based on by + // calculating the in between values using |value| and |values|. + auto update_windows_helper = [this](double progress, bool animate, + aura::Window* window, + const WindowValues& values) { + float opacity = gfx::Tween::FloatValueBetween( + progress, values.initial_opacity, values.target_opacity); + gfx::Transform transform = gfx::Tween::TransformValueBetween( + progress, values.initial_transform, values.target_transform); + + std::unique_ptr<ui::ScopedLayerAnimationSettings> settings; + if (animate) { + settings = std::make_unique<ui::ScopedLayerAnimationSettings>( + window->layer()->GetAnimator()); + // There are multiple animations run on a release event (app list, + // overview and the stored windows). We only want to act on one animation + // end, so only observe one of the animations. If overview is active, + // observe the shield widget of the grid, else observe |window_|. + UpdateSettings( + settings.get(), + this->window_ == window && + !Shell::Get()->window_selector_controller()->IsSelecting()); + } + window->layer()->SetOpacity(opacity); + window->SetTransform(transform); + }; + + aura::Window* backdrop_window = GetBackdropWindow(window_); + if (backdrop_window && backdrop_values_) { + update_windows_helper(progress, animate, backdrop_window, + *backdrop_values_); + } + + aura::Window* divider_window = GetDividerWindow(); + if (divider_window && divider_values_) { + update_windows_helper(progress, animate, divider_window, *divider_values_); + } + + for (const auto& descendant : transient_descendants_values_) { + update_windows_helper(progress, animate, descendant.first, + descendant.second); + } + + for (const auto& descendant : transient_descendants_values2_) { + update_windows_helper(progress, animate, descendant.first, + descendant.second); + } + + if (window2_) + update_windows_helper(progress, animate, window2_, window_values2_); + update_windows_helper(progress, animate, window_, window_values_); +} + +void HomeLauncherGestureHandler::RemoveObserversAndStopTracking() { + display_.set_id(display::kInvalidDisplayId); + backdrop_values_ = base::nullopt; + divider_values_ = base::nullopt; + last_event_location_ = base::nullopt; + mode_ = Mode::kNone; + + for (auto* window : hidden_windows_) + window->RemoveObserver(this); + hidden_windows_.clear(); + + for (const auto& descendant : transient_descendants_values_) + descendant.first->RemoveObserver(this); + transient_descendants_values_.clear(); + + if (window_) + window_->RemoveObserver(this); + window_ = nullptr; + + for (const auto& descendant : transient_descendants_values2_) + descendant.first->RemoveObserver(this); + transient_descendants_values2_.clear(); + + if (window2_) + window2_->RemoveObserver(this); + window2_ = nullptr; +} + +bool HomeLauncherGestureHandler::IsIdle() { + if (IsDragInProgress()) + return false; + + if (window_ && window_->layer()->GetAnimator()->is_animating()) + return false; + + if (window2_ && window2_->layer()->GetAnimator()->is_animating()) + return false; + + for (const auto& descendant : transient_descendants_values_) { + if (descendant.first->layer()->GetAnimator()->is_animating()) + return false; + } + + for (const auto& descendant : transient_descendants_values2_) { + if (descendant.first->layer()->GetAnimator()->is_animating()) + return false; + } + + return true; +} + +bool HomeLauncherGestureHandler::IsFinalStateShow() { + DCHECK_NE(Mode::kNone, mode_); + DCHECK(display_.is_valid()); + return last_event_location_ + ? IsLastEventInTopHalf(*last_event_location_, display_.work_area()) + : mode_ == Mode::kSlideUpToShow; +} + +bool HomeLauncherGestureHandler::SetUpWindows(Mode mode, aura::Window* window) { SplitViewController* split_view_controller = Shell::Get()->split_view_controller(); + const bool overview_active = + Shell::Get()->window_selector_controller()->IsSelecting(); const bool split_view_active = split_view_controller->IsSplitViewModeActive(); + if (window && (mode != Mode::kSlideDownToHide || overview_active || + split_view_active)) { + window_ = nullptr; + return false; + } + if (Shell::Get() ->app_list_controller() ->IsHomeLauncherEnabledInTabletMode() && - Shell::Get()->window_selector_controller()->IsSelecting() && - !split_view_active) { - DCHECK_EQ(Mode::kSwipeUpToShow, mode); - last_event_location_ = base::make_optional(gfx::Point()); - mode_ = mode; + overview_active && !split_view_active) { + DCHECK_EQ(Mode::kSlideUpToShow, mode); window_ = nullptr; return true; } - // We want the first window in the mru list, if it exists and is usable. + // Always hide split view windows if they exist. Otherwise, hide the specified + // window if it is not null. If non of above is true, we want the first window + // in the mru list, if it exists and is usable. auto windows = Shell::Get()->mru_window_tracker()->BuildWindowForCycleList(); - if (windows.empty() || !CanProcessWindow(windows[0], mode)) { + window_ = split_view_active + ? split_view_controller->GetDefaultSnappedWindow() + : (window ? window : (windows.empty() ? nullptr : windows[0])); + if (!CanProcessWindow(window_, mode)) { window_ = nullptr; return false; } + DCHECK(base::ContainsValue(windows, window_)); DCHECK_NE(Mode::kNone, mode); - last_event_location_ = base::make_optional(gfx::Point()); - mode_ = mode; base::RecordAction(base::UserMetricsAction( - mode_ == Mode::kSwipeDownToHide + mode == Mode::kSlideDownToHide ? "AppList_HomeLauncherToMRUWindowAttempt" : "AppList_CurrentWindowToHomeLauncherAttempt")); - window_ = split_view_active ? split_view_controller->GetDefaultSnappedWindow() - : windows[0]; - DCHECK(base::ContainsValue(windows, window_)); window_->AddObserver(this); base::EraseIf(windows, [this](aura::Window* elem) { return elem == this->window_; }); // Alter a second window if we are in split view mode with two windows // snapped. - if (mode == Mode::kSwipeUpToShow && + if (mode == Mode::kSlideUpToShow && split_view_controller->state() == SplitViewController::BOTH_SNAPPED) { DCHECK_GT(windows.size(), 0u); window2_ = split_view_controller->default_snap_position() == @@ -241,9 +630,10 @@ } // Show |window_| if we are swiping down to hide. - if (mode == Mode::kSwipeDownToHide) { + if (mode == Mode::kSlideDownToHide) { ScopedAnimationDisabler disable(window_); window_->Show(); + wm::ActivateWindow(window_); window_->layer()->SetOpacity(1.f); } @@ -319,8 +709,7 @@ // scroll, the home launcher will be visible. This is only needed when swiping // up, and not when overview mode is active. hidden_windows_.clear(); - if (mode_ == Mode::kSwipeUpToShow && - !Shell::Get()->window_selector_controller()->IsSelecting()) { + if (mode == Mode::kSlideUpToShow && !overview_active) { for (auto* window : windows) { if (window->IsVisible()) { hidden_windows_.push_back(window); @@ -331,310 +720,7 @@ } } - UpdateWindows(0.0, /*animate=*/false); return true; } -bool HomeLauncherGestureHandler::OnScrollEvent(const gfx::Point& location) { - if (!last_event_location_) - return false; - - last_event_location_ = base::make_optional(location); - double progress = GetHeightInWorkAreaAsRatio(location); - UpdateWindows(progress, /*animate=*/false); - return true; -} - -bool HomeLauncherGestureHandler::OnReleaseEvent(const gfx::Point& location) { - if (!last_event_location_) - return false; - - last_event_location_ = base::make_optional(location); - AnimateToFinalState(); - return true; -} - -void HomeLauncherGestureHandler::Cancel() { - if (!last_event_location_) - return; - - AnimateToFinalState(); - return; -} - -void HomeLauncherGestureHandler::OnWindowDestroying(aura::Window* window) { - if (window == window_) { - for (auto* hidden_window : hidden_windows_) - hidden_window->Show(); - - last_event_location_ = base::nullopt; - RemoveObserversAndStopTracking(); - return; - } - - if (window == window2_) { - DCHECK(window_); - window->RemoveObserver(this); - window2_ = nullptr; - return; - } - - if (transient_descendants_values_.find(window) != - transient_descendants_values_.end()) { - window->RemoveObserver(this); - transient_descendants_values_.erase(window); - return; - } - - if (transient_descendants_values2_.find(window) != - transient_descendants_values2_.end()) { - window->RemoveObserver(this); - transient_descendants_values2_.erase(window); - return; - } - - DCHECK(base::ContainsValue(hidden_windows_, window)); - window->RemoveObserver(this); - hidden_windows_.erase( - std::find(hidden_windows_.begin(), hidden_windows_.end(), window)); -} - -void HomeLauncherGestureHandler::OnTabletModeEnded() { - if (!last_event_location_) - return; - - // When leaving tablet mode advance to the end of the in progress scroll - // session or animation. - StopObservingImplicitAnimations(); - if (window_) - window_->layer()->GetAnimator()->StopAnimating(); - if (window2_) - window2_->layer()->GetAnimator()->StopAnimating(); - for (const auto& descendant : transient_descendants_values_) - descendant.first->layer()->GetAnimator()->StopAnimating(); - for (const auto& descendant : transient_descendants_values2_) - descendant.first->layer()->GetAnimator()->StopAnimating(); - UpdateWindows(IsLastEventInTopHalf(*last_event_location_) ? 1.0 : 0.0, - /*animate=*/false); - OnImplicitAnimationsCompleted(); -} - -void HomeLauncherGestureHandler::OnImplicitAnimationsCompleted() { - DCHECK(last_event_location_); - - float app_list_opacity = 1.f; - const bool last_event_top_half = IsLastEventInTopHalf(*last_event_location_); - if (Shell::Get()->window_selector_controller()->IsSelecting()) { - if (last_event_top_half) { - // Exit overview if event is released on the top half. This will also end - // splitview if it is active as SplitViewController observes overview mode - // ends. - Shell::Get()->window_selector_controller()->ToggleOverview( - WindowSelector::EnterExitOverviewType::kSwipeFromShelf); - } else { - app_list_opacity = 0.f; - } - } - - // Return the app list to its original opacity and transform without - // animation. - app_list_controller_->presenter()->UpdateYPositionAndOpacityForHomeLauncher( - display::Screen::GetScreen() - ->GetDisplayNearestPoint(*last_event_location_) - .work_area() - .y(), - app_list_opacity, base::NullCallback()); - - if (!window_) { - RemoveObserversAndStopTracking(); - return; - } - - // Explicitly exit split view if two windows are snapped. - if (last_event_top_half && Shell::Get()->split_view_controller()->state() == - SplitViewController::BOTH_SNAPPED) { - Shell::Get()->split_view_controller()->EndSplitView(); - } - - window_->SetTransform(window_values_.initial_transform); - window_->layer()->SetOpacity(window_values_.initial_opacity); - if (window2_) { - window2_->SetTransform(window_values2_.initial_transform); - window2_->layer()->SetOpacity(window_values2_.initial_opacity); - } - - if (last_event_top_half) { - ScopedAnimationDisabler disable(window_); - wm::GetWindowState(window_)->Minimize(); - - if (window2_) { - ScopedAnimationDisabler disable(window2_); - wm::GetWindowState(window2_)->Minimize(); - } - - // Minimize the hidden windows so they can be used normally with alt+tab - // and overview. Minimize in reverse order to preserve mru ordering. - std::reverse(hidden_windows_.begin(), hidden_windows_.end()); - for (auto* window : hidden_windows_) { - ScopedAnimationDisabler disable(window); - wm::GetWindowState(window)->Minimize(); - } - } else { - // Reshow all windows previously hidden. - for (auto* window : hidden_windows_) { - ScopedAnimationDisabler disable(window); - window->Show(); - } - } - - // Update the backdrop last as the backdrop controller listens for some state - // changes like minimizing above which may also alter the backdrop. - aura::Window* backdrop_window = GetBackdropWindow(window_); - if (backdrop_window) { - backdrop_window->SetTransform(gfx::Transform()); - backdrop_window->layer()->SetOpacity(1.f); - } - - RemoveObserversAndStopTracking(); -} - -void HomeLauncherGestureHandler::AnimateToFinalState() { - const bool hide_window = IsLastEventInTopHalf(*last_event_location_); - UpdateWindows(hide_window ? 1.0 : 0.0, /*animate=*/true); - - if (!hide_window && mode_ == Mode::kSwipeDownToHide) { - base::RecordAction( - base::UserMetricsAction("AppList_HomeLauncherToMRUWindow")); - } else if (hide_window && mode_ == Mode::kSwipeUpToShow) { - base::RecordAction( - base::UserMetricsAction("AppList_CurrentWindowToHomeLauncher")); - } -} - -void HomeLauncherGestureHandler::UpdateSettings( - ui::ScopedLayerAnimationSettings* settings, - bool observe) { - // TODO(sammiequon): The animation should change based on the distance to the - // end. - settings->SetTransitionDuration(kAnimationDurationMs); - settings->SetTweenType(gfx::Tween::LINEAR); - settings->SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - - if (observe) - settings->AddObserver(this); -} - -void HomeLauncherGestureHandler::UpdateWindows(double progress, bool animate) { - // Update full screen applist. - const gfx::Rect work_area = - display::Screen::GetScreen() - ->GetDisplayNearestPoint(*last_event_location_) - .work_area(); - const int y_position = - gfx::Tween::IntValueBetween(progress, work_area.bottom(), work_area.y()); - const float opacity = gfx::Tween::FloatValueBetween(progress, 0.f, 1.f); - app_list_controller_->presenter()->UpdateYPositionAndOpacityForHomeLauncher( - y_position, opacity, - animate ? base::BindRepeating(&HomeLauncherGestureHandler::UpdateSettings, - base::Unretained(this)) - : base::NullCallback()); - - // Update the overview grid if needed. - WindowSelectorController* controller = - Shell::Get()->window_selector_controller(); - if (controller->IsSelecting()) { - DCHECK_EQ(mode_, Mode::kSwipeUpToShow); - controller->window_selector()->UpdateGridAtLocationYPositionAndOpacity( - *last_event_location_, y_position - work_area.height(), 1.f - opacity, - work_area, - animate - ? base::BindRepeating(&HomeLauncherGestureHandler::UpdateSettings, - base::Unretained(this)) - : base::NullCallback()); - } - - if (!window_) - return; - - // Helper to update a single windows opacity and transform based on by - // calculating the in between values using |value| and |values|. - auto update_windows_helper = [this](double progress, bool animate, - aura::Window* window, - const WindowValues& values) { - float opacity = gfx::Tween::FloatValueBetween( - progress, values.initial_opacity, values.target_opacity); - gfx::Transform transform = gfx::Tween::TransformValueBetween( - progress, values.initial_transform, values.target_transform); - - std::unique_ptr<ui::ScopedLayerAnimationSettings> settings; - if (animate) { - settings = std::make_unique<ui::ScopedLayerAnimationSettings>( - window->layer()->GetAnimator()); - // There are multiple animations run on a release event (app list, - // overview and the stored windows). We only want to act on one animation - // end, so only observe one of the animations. If overview is active, - // observe the shield widget of the grid, else observe |window_|. - UpdateSettings( - settings.get(), - this->window_ == window && - !Shell::Get()->window_selector_controller()->IsSelecting()); - } - window->layer()->SetOpacity(opacity); - window->SetTransform(transform); - }; - - aura::Window* backdrop_window = GetBackdropWindow(window_); - if (backdrop_window && backdrop_values_) { - update_windows_helper(progress, animate, backdrop_window, - *backdrop_values_); - } - - aura::Window* divider_window = GetDividerWindow(); - if (divider_window && divider_values_) { - update_windows_helper(progress, animate, divider_window, *divider_values_); - } - - for (const auto& descendant : transient_descendants_values_) { - update_windows_helper(progress, animate, descendant.first, - descendant.second); - } - - for (const auto& descendant : transient_descendants_values2_) { - update_windows_helper(progress, animate, descendant.first, - descendant.second); - } - - if (window2_) - update_windows_helper(progress, animate, window2_, window_values2_); - update_windows_helper(progress, animate, window_, window_values_); -} - -void HomeLauncherGestureHandler::RemoveObserversAndStopTracking() { - backdrop_values_ = base::nullopt; - divider_values_ = base::nullopt; - last_event_location_ = base::nullopt; - mode_ = Mode::kNone; - - for (auto* window : hidden_windows_) - window->RemoveObserver(this); - hidden_windows_.clear(); - - for (const auto& descendant : transient_descendants_values_) - descendant.first->RemoveObserver(this); - transient_descendants_values_.clear(); - - if (window_) - window_->RemoveObserver(this); - window_ = nullptr; - - for (const auto& descendant : transient_descendants_values2_) - descendant.first->RemoveObserver(this); - transient_descendants_values2_.clear(); - - if (window2_) - window2_->RemoveObserver(this); - window2_ = nullptr; -} - } // namespace ash
diff --git a/ash/app_list/home_launcher_gesture_handler.h b/ash/app_list/home_launcher_gesture_handler.h index 15edc6f..44cf8c47 100644 --- a/ash/app_list/home_launcher_gesture_handler.h +++ b/ash/app_list/home_launcher_gesture_handler.h
@@ -37,11 +37,11 @@ enum class Mode { // There is no current scroll process. kNone, - // Swiping away the MRU window to display launcher. If in overview mode, - // swipes away overview mode as well. - kSwipeUpToShow, - // Swiping down the MRU window to hide launcher. - kSwipeDownToHide, + // Sliding up the MRU window to display launcher. If in overview mode, + // slides up overview mode as well. + kSlideUpToShow, + // Sliding down the MRU window to hide launcher. + kSlideDownToHide, }; explicit HomeLauncherGestureHandler( @@ -51,7 +51,7 @@ // Called by owner of this object when a gesture event is received. |location| // should be in screen coordinates. Returns false if the the gesture event // was not processed. - bool OnPressEvent(Mode mode); + bool OnPressEvent(Mode mode, const gfx::Point& location); bool OnScrollEvent(const gfx::Point& location); bool OnReleaseEvent(const gfx::Point& location); @@ -59,6 +59,13 @@ // |last_event_location_|. void Cancel(); + // Hide MRU window and show home launcher on specified display. + bool ShowHomeLauncher(const display::Display& display); + + // Hide home launcher and show MRU window on specified display. + bool HideHomeLauncherForWindow(const display::Display& display, + aura::Window* window); + bool IsDragInProgress() const { return last_event_location_.has_value(); } // TODO(sammiequon): Investigate if it is needed to observe potential window @@ -88,7 +95,7 @@ gfx::Transform target_transform; }; - // Animates the items based on |last_event_location_|. + // Animates the items based on IsFinalStateShow(). void AnimateToFinalState(); // Updates |settings| based on what we want for this class. This will listen @@ -105,6 +112,19 @@ // Stop observing all windows and remove their local pointers. void RemoveObserversAndStopTracking(); + // Returns true if there's no gesture dragging and animation. + bool IsIdle(); + + // Returns true if home launcher should run animation to show. Otherwise, + // returns false. + bool IsFinalStateShow(); + + // Sets up windows that will be used in dragging and animation. If |window| is + // not null for kSlideDownToHide mode, it will be set as the window to run + // slide down animation. |window| is not used for kSlideUpToShow mode. Returns + // true if windows are successfully set up. + bool SetUpWindows(Mode mode, aura::Window* window); + Mode mode_ = Mode::kNone; // The windows we are tracking. They are null if a drag is not underway, or if @@ -145,6 +165,9 @@ // Unowned and guaranteed to be non null for the lifetime of this. AppListControllerImpl* app_list_controller_; + // The display where the windows are being processed. + display::Display display_; + DISALLOW_COPY_AND_ASSIGN(HomeLauncherGestureHandler); };
diff --git a/ash/app_list/home_launcher_gesture_handler_unittest.cc b/ash/app_list/home_launcher_gesture_handler_unittest.cc index 7333e5f..e8f2e58 100644 --- a/ash/app_list/home_launcher_gesture_handler_unittest.cc +++ b/ash/app_list/home_launcher_gesture_handler_unittest.cc
@@ -54,26 +54,26 @@ // Tests that the gesture handler will not have a window to act on if there are // none in the mru list. TEST_F(HomeLauncherGestureHandlerTest, NeedsOneWindowToShow) { - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); EXPECT_FALSE(GetGestureHandler()->window()); auto window = CreateWindowForTesting(); - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); EXPECT_TRUE(GetGestureHandler()->window()); } // Tests that the gesture handler will not have a window to act on if there are // none in the mru list, or if they are not minimized. TEST_F(HomeLauncherGestureHandlerTest, NeedsOneMinimizedWindowToHide) { - GetGestureHandler()->OnPressEvent(Mode::kSwipeDownToHide); + GetGestureHandler()->OnPressEvent(Mode::kSlideDownToHide, gfx::Point()); EXPECT_FALSE(GetGestureHandler()->window()); auto window = CreateWindowForTesting(); - GetGestureHandler()->OnPressEvent(Mode::kSwipeDownToHide); + GetGestureHandler()->OnPressEvent(Mode::kSlideDownToHide, gfx::Point()); EXPECT_FALSE(GetGestureHandler()->window()); wm::GetWindowState(window.get())->Minimize(); - GetGestureHandler()->OnPressEvent(Mode::kSwipeDownToHide); + GetGestureHandler()->OnPressEvent(Mode::kSlideDownToHide, gfx::Point()); EXPECT_TRUE(GetGestureHandler()->window()); } @@ -90,7 +90,7 @@ // Test that the most recently activated window is visible, but the others are // not. ::wm::ActivateWindow(window1.get()); - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); EXPECT_TRUE(window1->IsVisible()); EXPECT_FALSE(window2->IsVisible()); EXPECT_FALSE(window3->IsVisible()); @@ -104,14 +104,14 @@ // Tests that when cancelling a scroll that was on the bottom half, the window // is still visible. - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); GetGestureHandler()->OnScrollEvent(gfx::Point(0, 300)); GetGestureHandler()->Cancel(); EXPECT_TRUE(window->IsVisible()); // Tests that when cancelling a scroll that was on the top half, the window is // now invisible. - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); GetGestureHandler()->OnScrollEvent(gfx::Point(0, 100)); GetGestureHandler()->Cancel(); EXPECT_FALSE(window->IsVisible()); @@ -133,7 +133,7 @@ window1->transform().To2dTranslation().y(); const int window2_initial_translation = window2->transform().To2dTranslation().y(); - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); EXPECT_FALSE(GetGestureHandler()->window()); // Tests that while scrolling the window transform changes. @@ -154,7 +154,7 @@ // Tests that after releasing on the bottom half, overview mode has been // exited, and the two windows have been minimized to show the home launcher. - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 100)); EXPECT_FALSE(controller->IsSelecting()); EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMinimized()); @@ -181,7 +181,7 @@ const int window2_initial_translation = window2->transform().To2dTranslation().y(); - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); EXPECT_EQ(window1.get(), GetGestureHandler()->window()); // Tests that while scrolling the window transforms change. @@ -201,7 +201,7 @@ // Tests that after releasing on the bottom half, overivew and splitview have // both been exited, and both windows are minimized to show the home launcher. - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 100)); EXPECT_FALSE(window_selector_controller->IsSelecting()); EXPECT_FALSE(split_view_controller->IsSplitViewModeActive()); @@ -227,7 +227,7 @@ // Make |window1| the most recent used window. It should be the main window in // HomeLauncherGestureHandler. ::wm::ActivateWindow(window1.get()); - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); EXPECT_EQ(window1.get(), GetGestureHandler()->window()); EXPECT_EQ(window2.get(), GetGestureHandler()->window2()); @@ -245,7 +245,7 @@ // Tests that after releasing on the bottom half, splitview has been ended, // and the two windows have been minimized to show the home launcher. - GetGestureHandler()->OnPressEvent(Mode::kSwipeUpToShow); + GetGestureHandler()->OnPressEvent(Mode::kSlideUpToShow, gfx::Point()); GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 100)); EXPECT_FALSE(split_view_controller->IsSplitViewModeActive()); EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMinimized()); @@ -263,7 +263,7 @@ std::unique_ptr<aura::Window> CreateWindowForTesting() override { std::unique_ptr<aura::Window> window = HomeLauncherGestureHandlerTest::CreateWindowForTesting(); - if (mode_ == Mode::kSwipeDownToHide) + if (mode_ == Mode::kSlideDownToHide) wm::GetWindowState(window.get())->Minimize(); return window; } @@ -277,14 +277,14 @@ INSTANTIATE_TEST_CASE_P(, HomeLauncherModeGestureHandlerTest, - testing::Values(Mode::kSwipeDownToHide, - Mode::kSwipeUpToShow)); + testing::Values(Mode::kSlideDownToHide, + Mode::kSlideUpToShow)); // Tests that the window transform and opacity changes as we scroll. TEST_P(HomeLauncherModeGestureHandlerTest, TransformAndOpacityChangesOnScroll) { auto window = CreateWindowForTesting(); - GetGestureHandler()->OnPressEvent(mode_); + GetGestureHandler()->OnPressEvent(mode_, gfx::Point()); ASSERT_TRUE(GetGestureHandler()->window()); // Test that on scrolling to a point on the top half of the work area, the @@ -312,7 +312,7 @@ auto window2 = CreateWindowForTesting(); auto window1 = CreateWindowForTesting(); - GetGestureHandler()->OnPressEvent(mode_); + GetGestureHandler()->OnPressEvent(mode_, gfx::Point()); ASSERT_TRUE(GetGestureHandler()->window()); ASSERT_FALSE(window2->IsVisible()); ASSERT_FALSE(window3->IsVisible()); @@ -327,7 +327,7 @@ EXPECT_EQ(gfx::Transform(), window1->transform()); EXPECT_EQ(1.f, window1->layer()->opacity()); - if (mode_ == Mode::kSwipeDownToHide) + if (mode_ == Mode::kSlideDownToHide) return; // The other windows return to their original visibility if mode is swiping @@ -344,7 +344,7 @@ auto window2 = CreateWindowForTesting(); auto window1 = CreateWindowForTesting(); - GetGestureHandler()->OnPressEvent(mode_); + GetGestureHandler()->OnPressEvent(mode_, gfx::Point()); ASSERT_TRUE(GetGestureHandler()->window()); ASSERT_FALSE(window2->IsVisible()); ASSERT_FALSE(window3->IsVisible()); @@ -372,7 +372,7 @@ ::wm::AddTransientChild(parent.get(), child.get()); // |parent| should be the window that is getting hidden. - GetGestureHandler()->OnPressEvent(mode_); + GetGestureHandler()->OnPressEvent(mode_, gfx::Point()); ASSERT_EQ(parent.get(), GetGestureHandler()->window()); // Tests that after scrolling to the halfway point, the transient child's @@ -394,7 +394,7 @@ TEST_P(HomeLauncherModeGestureHandlerTest, EndScrollOnTabletModeEnd) { auto window = CreateWindowForTesting(); - GetGestureHandler()->OnPressEvent(mode_); + GetGestureHandler()->OnPressEvent(mode_, gfx::Point()); ASSERT_TRUE(GetGestureHandler()->window()); // Scroll to a point above the halfway mark of the work area. @@ -421,19 +421,19 @@ ::wm::ActivateWindow(window1.get()); // For swipe down to hide launcher, all windows must be minimized. - if (mode_ == Mode::kSwipeDownToHide) { + if (mode_ == Mode::kSlideDownToHide) { wm::GetWindowState(window2.get())->Minimize(); wm::GetWindowState(window1.get())->Minimize(); } // Tests that the variables which change when dragging are as expected. - GetGestureHandler()->OnPressEvent(mode_); + GetGestureHandler()->OnPressEvent(mode_, gfx::Point()); EXPECT_EQ(window1.get(), GetGestureHandler()->window()); EXPECT_TRUE(GetGestureHandler()->last_event_location_); EXPECT_EQ(mode_, GetGestureHandler()->mode_); // We only need to hide windows when swiping up, so this will only be non // empty in that case. - if (mode_ == Mode::kSwipeUpToShow) + if (mode_ == Mode::kSlideUpToShow) EXPECT_FALSE(GetGestureHandler()->hidden_windows_.empty()); EXPECT_FALSE(GetGestureHandler()->transient_descendants_values_.empty());
diff --git a/ash/ash_service.cc b/ash/ash_service.cc index 8d20620..826e810 100644 --- a/ash/ash_service.cc +++ b/ash/ash_service.cc
@@ -118,7 +118,7 @@ discardable_shared_memory_manager_ = std::make_unique<discardable_memory::DiscardableSharedMemoryManager>(); - gpu_host_ = std::make_unique<ws::gpu_host::DefaultGpuHost>( + gpu_host_ = std::make_unique<ws::gpu_host::GpuHost>( this, context()->connector(), discardable_shared_memory_manager_.get()); host_frame_sink_manager_ = std::make_unique<viz::HostFrameSinkManager>();
diff --git a/ash/ash_service.h b/ash/ash_service.h index 800465b5..0a256f1 100644 --- a/ash/ash_service.h +++ b/ash/ash_service.h
@@ -53,7 +53,7 @@ class HostContextFactory; class InputDeviceController; namespace gpu_host { -class DefaultGpuHost; +class GpuHost; } // namespace gpu_host } // namespace ws @@ -108,7 +108,7 @@ std::unique_ptr<discardable_memory::DiscardableSharedMemoryManager> discardable_shared_memory_manager_; - std::unique_ptr<ws::gpu_host::DefaultGpuHost> gpu_host_; + std::unique_ptr<ws::gpu_host::GpuHost> gpu_host_; std::unique_ptr<viz::HostFrameSinkManager> host_frame_sink_manager_;
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index 9617ec40..726113e 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -111,6 +111,7 @@ "tablet_mode.cc", "tablet_mode.h", "wallpaper_types.h", + "window_animation_types.h", "window_pin_type.cc", "window_pin_type.h", "window_properties.cc",
diff --git a/ash/wm/window_animation_types.h b/ash/public/cpp/window_animation_types.h similarity index 63% rename from ash/wm/window_animation_types.h rename to ash/public/cpp/window_animation_types.h index eb30c35..f5a4f5a 100644 --- a/ash/wm/window_animation_types.h +++ b/ash/public/cpp/window_animation_types.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_WM_WINDOW_ANIMATION_TYPES_H_ -#define ASH_WM_WINDOW_ANIMATION_TYPES_H_ +#ifndef ASH_PUBLIC_CPP_WINDOW_ANIMATION_TYPES_H_ +#define ASH_PUBLIC_CPP_WINDOW_ANIMATION_TYPES_H_ #include "ui/wm/core/window_animations.h" @@ -17,10 +17,13 @@ WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE = ::wm::WINDOW_VISIBILITY_ANIMATION_MAX, // Fade in/out using brightness and grayscale web filters. - WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE + WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE, + // Window slides down from above screen to show and, meanwhile, home launcher + // slides down off screen. + WINDOW_VISIBILITY_ANIMATION_TYPE_SLIDE_DOWN }; } // namespace wm } // namespace ash -#endif // ASH_WM_WINDOW_ANIMATION_TYPES_H_ +#endif // ASH_PUBLIC_CPP_WINDOW_ANIMATION_TYPES_H_
diff --git a/ash/shelf/app_list_shelf_item_delegate.cc b/ash/shelf/app_list_shelf_item_delegate.cc index 1ca93e52..1c77f646 100644 --- a/ash/shelf/app_list_shelf_item_delegate.cc +++ b/ash/shelf/app_list_shelf_item_delegate.cc
@@ -8,6 +8,7 @@ #include <utility> #include "ash/app_list/app_list_controller_impl.h" +#include "ash/app_list/home_launcher_gesture_handler.h" #include "ash/public/cpp/app_list/app_list_constants.h" #include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/shelf_model.h" @@ -18,6 +19,7 @@ #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" +#include "ui/display/manager/display_manager.h" namespace ash { @@ -39,41 +41,51 @@ return; } - // Whether to perform the "back" action for the app list. It will only be - // performed if other actions are not performed. - bool back_action = true; + // Whether the this action is handled. + bool handled = false; - // End overview mode. - if (Shell::Get()->window_selector_controller()->IsSelecting()) { - Shell::Get()->window_selector_controller()->ToggleOverview( - WindowSelector::EnterExitOverviewType::kWindowsMinimized); - back_action = false; + HomeLauncherGestureHandler* home_launcher_gesture_handler = + Shell::Get()->app_list_controller()->home_launcher_gesture_handler(); + if (home_launcher_gesture_handler) { + handled = home_launcher_gesture_handler->ShowHomeLauncher( + Shell::Get()->display_manager()->GetDisplayForId(display_id)); } - // End split view mode. - if (Shell::Get()->split_view_controller()->IsSplitViewModeActive()) { - Shell::Get()->split_view_controller()->EndSplitView( - SplitViewController::EndReason::kHomeLauncherPressed); - back_action = false; - } - - // Minimize all windows that aren't the app list in reverse order to preserve - // the mru ordering. - aura::Window* app_list_container = - Shell::Get()->GetPrimaryRootWindow()->GetChildById( - kShellWindowId_AppListTabletModeContainer); - aura::Window::Windows windows = - Shell::Get()->mru_window_tracker()->BuildWindowForCycleList(); - std::reverse(windows.begin(), windows.end()); - for (auto* window : windows) { - if (!app_list_container->Contains(window) && - !wm::GetWindowState(window)->IsMinimized()) { - wm::GetWindowState(window)->Minimize(); - back_action = false; + if (!handled) { + if (Shell::Get()->window_selector_controller()->IsSelecting()) { + // End overview mode. + Shell::Get()->window_selector_controller()->ToggleOverview( + WindowSelector::EnterExitOverviewType::kWindowsMinimized); + handled = true; + } + if (Shell::Get()->split_view_controller()->IsSplitViewModeActive()) { + // End split view mode. + Shell::Get()->split_view_controller()->EndSplitView( + SplitViewController::EndReason::kHomeLauncherPressed); + handled = true; } } - if (back_action) + if (!handled) { + // Minimize all windows that aren't the app list in reverse order to + // preserve the mru ordering. + aura::Window* app_list_container = + Shell::Get()->GetPrimaryRootWindow()->GetChildById( + kShellWindowId_AppListTabletModeContainer); + aura::Window::Windows windows = + Shell::Get()->mru_window_tracker()->BuildWindowForCycleList(); + std::reverse(windows.begin(), windows.end()); + for (auto* window : windows) { + if (!app_list_container->Contains(window) && + !wm::GetWindowState(window)->IsMinimized()) { + wm::GetWindowState(window)->Minimize(); + handled = true; + } + } + } + + // Perform the "back" action for the app list. + if (!handled) Shell::Get()->app_list_controller()->Back(); std::move(callback).Run(SHELF_ACTION_APP_LIST_SHOWN, base::nullopt);
diff --git a/ash/shelf/app_list_shelf_item_delegate_unittest.cc b/ash/shelf/app_list_shelf_item_delegate_unittest.cc index 691fdd1..076d330a 100644 --- a/ash/shelf/app_list_shelf_item_delegate_unittest.cc +++ b/ash/shelf/app_list_shelf_item_delegate_unittest.cc
@@ -49,8 +49,8 @@ std::unique_ptr<ui::Event> test_event = std::make_unique<ui::KeyEvent>( ui::EventType::ET_MOUSE_PRESSED, ui::VKEY_UNKNOWN, ui::EF_NONE); delegate()->ItemSelected( - std::move(test_event), - /*display_id=*/0, ShelfLaunchSource::LAUNCH_FROM_UNKNOWN, + std::move(test_event), GetPrimaryDisplay().id(), + ShelfLaunchSource::LAUNCH_FROM_UNKNOWN, base::BindOnce( [](ash::ShelfAction, base::Optional<ash::MenuItemList>) {})); ASSERT_TRUE(wm::GetWindowState(w1.get())->IsMinimized());
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc index 19adaee..ab65fc36 100644 --- a/ash/shelf/shelf.cc +++ b/ash/shelf/shelf.cc
@@ -209,7 +209,7 @@ : 0; } -gfx::Rect Shelf::GetIdealBounds() const { +gfx::Rect Shelf::GetIdealBounds() { return shelf_layout_manager_->GetIdealBounds(); } @@ -298,21 +298,6 @@ return GetStatusAreaWidget()->GetSystemTrayAnchor(); } -gfx::Rect Shelf::GetSystemTrayAnchorRect() const { - gfx::Rect shelf_bounds = GetIdealBounds(); - switch (alignment_) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - return gfx::Rect(shelf_bounds.right(), shelf_bounds.y(), 0, 0); - case SHELF_ALIGNMENT_LEFT: - return gfx::Rect(shelf_bounds.right(), shelf_bounds.bottom(), 0, 0); - case SHELF_ALIGNMENT_RIGHT: - return gfx::Rect(shelf_bounds.x(), shelf_bounds.bottom(), 0, 0); - } - NOTREACHED(); - return gfx::Rect(); -} - bool Shelf::ShouldHideOnSecondaryDisplay(session_manager::SessionState state) { if (Shell::GetPrimaryRootWindowController()->shelf() == this) return false;
diff --git a/ash/shelf/shelf.h b/ash/shelf/shelf.h index 1bd44f4..9a6418d 100644 --- a/ash/shelf/shelf.h +++ b/ash/shelf/shelf.h
@@ -102,7 +102,7 @@ int GetDockedMagnifierHeight() const; // Returns the ideal bounds of the shelf assuming it is visible. - gfx::Rect GetIdealBounds() const; + gfx::Rect GetIdealBounds(); gfx::Rect GetUserWorkAreaBounds() const; @@ -140,12 +140,6 @@ // bubble will be anchored. See also: StatusAreaWidget::GetSystemTrayAnchor() TrayBackgroundView* GetSystemTrayAnchor() const; - // Get the anchor rect that the system tray bubble and the notification center - // bubble will be anchored. - // x() and y() designates anchor point, but width() and height() are dummy. - // See also: BubbleDialogDelegateView::GetBubbleBounds() - gfx::Rect GetSystemTrayAnchorRect() const; - void set_is_tablet_mode_animation_running(bool value) { is_tablet_mode_animation_running_ = value; }
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc index 9e84ac4..59eef685 100644 --- a/ash/shelf/shelf_layout_manager.cc +++ b/ash/shelf/shelf_layout_manager.cc
@@ -209,7 +209,7 @@ state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN)); } -gfx::Rect ShelfLayoutManager::GetIdealBounds() const { +gfx::Rect ShelfLayoutManager::GetIdealBounds() { const int shelf_size = ShelfConstants::shelf_size(); aura::Window* shelf_window = shelf_widget_->GetNativeWindow(); gfx::Rect rect(screen_util::GetDisplayBoundsInParent(shelf_window)); @@ -1214,7 +1214,8 @@ Shell::Get()->app_list_controller()->home_launcher_gesture_handler(); if (home_launcher_handler && visibility_state() == SHELF_VISIBLE && home_launcher_handler->OnPressEvent( - HomeLauncherGestureHandler::Mode::kSwipeUpToShow)) { + HomeLauncherGestureHandler::Mode::kSlideUpToShow, + gesture_in_screen.location())) { gesture_drag_status_ = GESTURE_DRAG_APPLIST_IN_PROGRESS; return; }
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h index 7bf88b9f..10b7de5 100644 --- a/ash/shelf/shelf_layout_manager.h +++ b/ash/shelf/shelf_layout_manager.h
@@ -80,7 +80,7 @@ bool IsVisible() const; // Returns the ideal bounds of the shelf assuming it is visible. - gfx::Rect GetIdealBounds() const; + gfx::Rect GetIdealBounds(); // Returns the preferred size of the shelf for the target visibility state. gfx::Size GetPreferredSize();
diff --git a/ash/system/tray/tray_bubble_view.cc b/ash/system/tray/tray_bubble_view.cc index 275207ee..162dfc02d 100644 --- a/ash/system/tray/tray_bubble_view.cc +++ b/ash/system/tray/tray_bubble_view.cc
@@ -231,11 +231,6 @@ auto layout = std::make_unique<BottomAlignedBoxLayout>(this); layout->SetDefaultFlex(1); layout_ = SetLayoutManager(std::move(layout)); - - if (init_params.anchor_mode == AnchorMode::kRect) { - SetAnchorView(nullptr); - SetAnchorRect(init_params.anchor_rect); - } } TrayBubbleView::~TrayBubbleView() { @@ -311,20 +306,9 @@ } void TrayBubbleView::ChangeAnchorView(views::View* anchor_view) { - DCHECK(params_.anchor_mode == AnchorMode::kView); BubbleDialogDelegateView::SetAnchorView(anchor_view); } -void TrayBubbleView::ChangeAnchorRect(const gfx::Rect& rect) { - DCHECK(params_.anchor_mode == AnchorMode::kRect); - BubbleDialogDelegateView::SetAnchorRect(rect); -} - -void TrayBubbleView::ChangeAnchorAlignment( - TrayBubbleView::AnchorAlignment alignment) { - SetArrow(GetArrowAlignment(alignment)); -} - int TrayBubbleView::GetDialogButtons() const { return ui::DIALOG_BUTTON_NONE; }
diff --git a/ash/system/tray/tray_bubble_view.h b/ash/system/tray/tray_bubble_view.h index f3c78eabf..22954c9 100644 --- a/ash/system/tray/tray_bubble_view.h +++ b/ash/system/tray/tray_bubble_view.h
@@ -12,7 +12,6 @@ #include "base/optional.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/events/event.h" -#include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/mouse_watcher.h" @@ -86,23 +85,12 @@ DISALLOW_COPY_AND_ASSIGN(Delegate); }; - // Anchor mode being set at creation. - enum class AnchorMode { - // Anchor to |anchor_view|. This is the default. - kView, - // Anchor to |anchor_rect|. Used for anchoring to the shelf. - kRect - }; - struct ASH_EXPORT InitParams { InitParams(); InitParams(const InitParams& other); Delegate* delegate = nullptr; gfx::NativeWindow parent_window = nullptr; View* anchor_view = nullptr; - AnchorMode anchor_mode = AnchorMode::kView; - // Only used if anchor_mode == AnchorMode::kRect. - gfx::Rect anchor_rect; AnchorAlignment anchor_alignment = ANCHOR_ALIGNMENT_BOTTOM; int min_width = 0; int max_width = 0; @@ -147,16 +135,8 @@ void ResetDelegate(); // Anchors the bubble to |anchor_view|. - // Only eligible if anchor_mode == AnchorMode::kView. void ChangeAnchorView(views::View* anchor_view); - // Anchors the bubble to |anchor_rect|. Exclusive with ChangeAnchorView(). - // Only eligible if anchor_mode == AnchorMode::kRect. - void ChangeAnchorRect(const gfx::Rect& anchor_rect); - - // Change anchor alignment mode when anchoring either the rect or view. - void ChangeAnchorAlignment(AnchorAlignment alignment); - Delegate* delegate() { return delegate_; } void set_gesture_dragging(bool dragging) { is_gesture_dragging_ = dragging; }
diff --git a/ash/system/unified/unified_system_tray_bubble.cc b/ash/system/unified/unified_system_tray_bubble.cc index 1b6fe33..a6ca4b62 100644 --- a/ash/system/unified/unified_system_tray_bubble.cc +++ b/ash/system/unified/unified_system_tray_bubble.cc
@@ -94,8 +94,6 @@ init_params.parent_window = tray->GetBubbleWindowContainer(); init_params.anchor_view = tray->shelf()->GetSystemTrayAnchor()->GetBubbleAnchor(); - init_params.anchor_mode = TrayBubbleView::AnchorMode::kRect; - init_params.anchor_rect = tray->shelf()->GetSystemTrayAnchorRect(); init_params.corner_radius = kUnifiedTrayCornerRadius; init_params.has_shadow = false; init_params.show_by_click = show_by_click; @@ -303,8 +301,22 @@ int max_height = CalculateMaxHeight(); unified_view_->SetMaxHeight(max_height); bubble_view_->SetMaxHeight(max_height); - bubble_view_->ChangeAnchorAlignment(tray_->GetAnchorAlignment()); - bubble_view_->ChangeAnchorRect(tray_->shelf()->GetSystemTrayAnchorRect()); + // If the bubble is open while switching to and from tablet mode, change the + // bubble anchor if needed. The new anchor view may also have a translation + // applied to it so shift the bubble bounds so that it appears in the correct + // location. + bubble_view_->ChangeAnchorView( + tray_->shelf()->GetSystemTrayAnchor()->GetBubbleAnchor()); + gfx::Rect bounds = + bubble_view_->GetWidget()->GetNativeWindow()->GetBoundsInScreen(); + const gfx::Vector2dF translation = tray_->shelf() + ->GetSystemTrayAnchor() + ->layer() + ->transform() + .To2dTranslation(); + bounds.set_x(bounds.x() - translation.x()); + bounds.set_y(bounds.y() - translation.y()); + bubble_view_->GetWidget()->GetNativeWindow()->SetBounds(bounds); } void UnifiedSystemTrayBubble::CreateBlurLayerForAnimation() {
diff --git a/ash/wallpaper/wallpaper_view.cc b/ash/wallpaper/wallpaper_view.cc index 190eaa8..fa9b2468 100644 --- a/ash/wallpaper/wallpaper_view.cc +++ b/ash/wallpaper/wallpaper_view.cc
@@ -6,13 +6,13 @@ #include "ash/public/cpp/login_constants.h" #include "ash/public/cpp/wallpaper_types.h" +#include "ash/public/cpp/window_animation_types.h" #include "ash/root_window_controller.h" #include "ash/session/session_controller.h" #include "ash/shell.h" #include "ash/wallpaper/wallpaper_controller.h" #include "ash/wallpaper/wallpaper_widget_controller.h" #include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/window_animation_types.h" #include "ui/aura/window.h" #include "ui/display/display.h" #include "ui/display/manager/display_manager.h"
diff --git a/ash/wm/base_state.cc b/ash/wm/base_state.cc index 6c9fab23..512d3e3 100644 --- a/ash/wm/base_state.cc +++ b/ash/wm/base_state.cc
@@ -4,11 +4,11 @@ #include "ash/wm/base_state.h" +#include "ash/public/cpp/window_animation_types.h" #include "ash/public/cpp/window_state_type.h" #include "ash/screen_util.h" #include "ash/shell.h" #include "ash/wm/splitview/split_view_controller.h" -#include "ash/wm/window_animation_types.h" #include "ash/wm/window_positioning_utils.h" #include "ash/wm/wm_event.h" #include "ui/aura/client/aura_constants.h"
diff --git a/ash/wm/client_controlled_state.cc b/ash/wm/client_controlled_state.cc index 1d0843cd..8bfc26c 100644 --- a/ash/wm/client_controlled_state.cc +++ b/ash/wm/client_controlled_state.cc
@@ -5,12 +5,12 @@ #include "ash/wm/client_controlled_state.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_animation_types.h" #include "ash/public/cpp/window_state_type.h" #include "ash/root_window_controller.h" #include "ash/screen_util.h" #include "ash/shell.h" #include "ash/wm/screen_pinning_controller.h" -#include "ash/wm/window_animation_types.h" #include "ash/wm/window_parenting_utils.h" #include "ash/wm/window_positioning_utils.h" #include "ash/wm/window_state.h"
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc index bedaf47..757c4bd2 100644 --- a/ash/wm/default_state.cc +++ b/ash/wm/default_state.cc
@@ -5,12 +5,12 @@ #include "ash/wm/default_state.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_animation_types.h" #include "ash/public/cpp/window_state_type.h" #include "ash/root_window_controller.h" #include "ash/screen_util.h" #include "ash/shell.h" #include "ash/wm/screen_pinning_controller.h" -#include "ash/wm/window_animation_types.h" #include "ash/wm/window_parenting_utils.h" #include "ash/wm/window_positioning_utils.h" #include "ash/wm/window_state.h"
diff --git a/ash/wm/lock_window_state.cc b/ash/wm/lock_window_state.cc index 14b3689..2946794 100644 --- a/ash/wm/lock_window_state.cc +++ b/ash/wm/lock_window_state.cc
@@ -7,10 +7,10 @@ #include <memory> #include <utility> +#include "ash/public/cpp/window_animation_types.h" #include "ash/screen_util.h" #include "ash/shelf/shelf.h" #include "ash/wm/lock_layout_manager.h" -#include "ash/wm/window_animation_types.h" #include "ash/wm/window_state.h" #include "ash/wm/window_state_delegate.h" #include "ash/wm/window_state_util.h"
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc index 92b29f4..d14557d 100644 --- a/ash/wm/overview/window_selector.cc +++ b/ash/wm/overview/window_selector.cc
@@ -728,15 +728,13 @@ } void WindowSelector::UpdateGridAtLocationYPositionAndOpacity( - const gfx::Point& location, + int64_t display_id, int new_y, float opacity, const gfx::Rect& work_area, UpdateAnimationSettingsCallback callback) { - WindowGrid* grid = - GetGridWithRootWindow(display::Screen::GetScreen() - ->GetWindowAtScreenPoint(location) - ->GetRootWindow()); + WindowGrid* grid = GetGridWithRootWindow( + ash::Shell::Get()->GetRootWindowForDisplayId(display_id)); if (grid) grid->UpdateYPositionAndOpacity(new_y, opacity, work_area, callback); }
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h index abd7427..46be49f 100644 --- a/ash/wm/overview/window_selector.h +++ b/ash/wm/overview/window_selector.h
@@ -208,7 +208,7 @@ // Shifts and fades the grid in |grid_list_| associated with |location|. void UpdateGridAtLocationYPositionAndOpacity( - const gfx::Point& location, + int64_t display_id, int new_y, float opacity, const gfx::Rect& work_area,
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc index e6f3615..f27e2328 100644 --- a/ash/wm/splitview/split_view_controller_unittest.cc +++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -3202,7 +3202,7 @@ EndScrollSequence( start, 10, timestamp, window.get(), /*is_fling=*/true, /*velocity_y=*/ - TabletModeAppWindowDragController::kFlingToOverviewThreshold - 10.f); + TabletModeWindowDragDelegate::kFlingToOverviewThreshold - 10.f); EXPECT_FALSE(window_selector_controller->IsSelecting()); // FLING the window with large veloicty (larger than @@ -3214,7 +3214,7 @@ EndScrollSequence( start, 10, timestamp, window.get(), /*is_fling=*/true, /*velocity_y=*/ - TabletModeAppWindowDragController::kFlingToOverviewThreshold + 10.f); + TabletModeWindowDragDelegate::kFlingToOverviewThreshold + 10.f); EXPECT_TRUE(window_selector_controller->IsSelecting()); } @@ -3341,12 +3341,12 @@ split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window.get()); const float long_scroll_delta = display_bounds.height() / 4 + 5; - float large_velocity = TabletModeAppWindowDragController:: - kFlingToOverviewFromSnappingAreaThreshold + - 10.f; - float small_velocity = TabletModeAppWindowDragController:: - kFlingToOverviewFromSnappingAreaThreshold - - 10.f; + float large_velocity = + TabletModeWindowDragDelegate::kFlingToOverviewFromSnappingAreaThreshold + + 10.f; + float small_velocity = + TabletModeWindowDragDelegate::kFlingToOverviewFromSnappingAreaThreshold - + 10.f; gfx::Point start; base::TimeTicks timestamp = base::TimeTicks::Now(); @@ -3412,9 +3412,9 @@ gfx::Rect display_bounds = split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window1.get()); const float long_scroll_y = display_bounds.bottom() - 10; - float large_velocity = TabletModeAppWindowDragController:: - kFlingToOverviewFromSnappingAreaThreshold + - 10.f; + float large_velocity = + TabletModeWindowDragDelegate::kFlingToOverviewFromSnappingAreaThreshold + + 10.f; const gfx::Point start; // Fling the window in left snapping area to left should still snap the
diff --git a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc index 6a05e8f..5e69034 100644 --- a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc +++ b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.cc
@@ -5,27 +5,17 @@ #include "ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h" #include "ash/shell.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/splitview/split_view_drag_indicators.h" #include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h" #include "ash/wm/window_state.h" #include "ui/base/hit_test.h" +#include "ui/views/widget/widget.h" #include "ui/wm/core/coordinate_conversion.h" namespace ash { namespace { -// Return the location of |event| in screen coordinates. -gfx::Point GetEventLocationInScreen(const ui::GestureEvent* event) { - gfx::Point location_in_screen(event->location()); - ::wm::ConvertPointToScreen(static_cast<aura::Window*>(event->target()), - &location_in_screen); - return location_in_screen; -} - // The drag delegate for app windows. It not only includes the logic in // TabletModeWindowDragDelegate, but also has special logic for app windows. class TabletModeAppWindowDragDelegate : public TabletModeWindowDragDelegate { @@ -63,7 +53,8 @@ bool TabletModeAppWindowDragController::DragWindowFromTop( ui::GestureEvent* event) { - previous_location_in_screen_ = GetEventLocationInScreen(event); + previous_location_in_screen_ = + drag_delegate_->GetEventLocationInScreen(event); if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) return StartWindowDrag(event); @@ -75,12 +66,16 @@ return true; } - if (event->type() == ui::ET_GESTURE_SCROLL_END || - event->type() == ui::ET_SCROLL_FLING_START) { + if (event->type() == ui::ET_GESTURE_SCROLL_END) { EndWindowDrag(event, wm::WmToplevelWindowEventHandler::DragResult::SUCCESS); return true; } + if (event->type() == ui::ET_SCROLL_FLING_START) { + FlingOrSwipe(event); + return true; + } + EndWindowDrag(event, wm::WmToplevelWindowEventHandler::DragResult::REVERT); return false; } @@ -92,8 +87,9 @@ if (!widget) return false; - drag_delegate_->StartWindowDrag(widget->GetNativeWindow(), - GetEventLocationInScreen(event)); + drag_delegate_->StartWindowDrag( + widget->GetNativeWindow(), + drag_delegate_->GetEventLocationInScreen(event)); return true; } @@ -101,68 +97,19 @@ ui::GestureEvent* event) { // Update the dragged window's tranform during dragging. drag_delegate_->ContinueWindowDrag( - GetEventLocationInScreen(event), + drag_delegate_->GetEventLocationInScreen(event), TabletModeWindowDragDelegate::UpdateDraggedWindowType::UPDATE_TRANSFORM); } -bool TabletModeAppWindowDragController::ShouldFlingIntoOverview( - ui::GestureEvent* event) { - if (event->type() != ui::ET_SCROLL_FLING_START) - return false; - - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); - const gfx::Point location_in_screen = GetEventLocationInScreen(event); - const IndicatorState indicator_state = - drag_delegate_->GetIndicatorState(location_in_screen); - const bool is_landscape = - split_view_controller->IsCurrentScreenOrientationLandscape(); - const float velocity = is_landscape ? event->details().velocity_x() - : event->details().velocity_y(); - - // Drop the window into overview if fling with large enough velocity to the - // opposite snap position when preview area is shown. - if (split_view_controller->IsCurrentScreenOrientationPrimary()) { - if (indicator_state == IndicatorState::kPreviewAreaLeft) - return velocity > kFlingToOverviewFromSnappingAreaThreshold; - else if (indicator_state == IndicatorState::kPreviewAreaRight) - return -velocity > kFlingToOverviewFromSnappingAreaThreshold; - } else { - if (indicator_state == IndicatorState::kPreviewAreaLeft) - return -velocity > kFlingToOverviewFromSnappingAreaThreshold; - else if (indicator_state == IndicatorState::kPreviewAreaRight) - return velocity > kFlingToOverviewFromSnappingAreaThreshold; - } - - const SplitViewController::State snap_state = split_view_controller->state(); - const int end_position = - is_landscape ? location_in_screen.x() : location_in_screen.y(); - // Fling the window when splitview is active. Since each snapping area in - // splitview has a corresponding snap position. Fling the window to the - // opposite position of the area's snap position with large enough velocity - // should drop the window into overview grid. - if (snap_state == SplitViewController::LEFT_SNAPPED || - snap_state == SplitViewController::RIGHT_SNAPPED) { - return end_position > split_view_controller->divider_position() - ? -velocity > kFlingToOverviewFromSnappingAreaThreshold - : velocity > kFlingToOverviewFromSnappingAreaThreshold; - } - - // Consider only the velocity_y if splitview is not active and preview area is - // not shown. - return event->details().velocity_y() > kFlingToOverviewThreshold; -} - void TabletModeAppWindowDragController::EndWindowDrag( ui::GestureEvent* event, wm::WmToplevelWindowEventHandler::DragResult result) { - if (ShouldFlingIntoOverview(event)) { - DCHECK(Shell::Get()->window_selector_controller()->IsSelecting()); - Shell::Get()->window_selector_controller()->window_selector()->AddItem( - drag_delegate_->dragged_window(), /*reposition=*/true, - /*animate=*/false); - } - drag_delegate_->EndWindowDrag(result, GetEventLocationInScreen(event)); + drag_delegate_->EndWindowDrag( + result, drag_delegate_->GetEventLocationInScreen(event)); +} + +void TabletModeAppWindowDragController::FlingOrSwipe(ui::GestureEvent* event) { + drag_delegate_->FlingOrSwipe(event); } void TabletModeAppWindowDragController::OnDisplayMetricsChanged(
diff --git a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h index 21d3ce3..6875cf83 100644 --- a/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h +++ b/ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h
@@ -21,14 +21,6 @@ class ASH_EXPORT TabletModeAppWindowDragController : public display::DisplayObserver { public: - // Threshold of the fling velocity to drop the dragged window into overview if - // fling from the top of the display. - static constexpr float kFlingToOverviewThreshold = 2000.f; - - // Threshold of the fling velocity to drop the dragged window into overview if - // fling inside preview area or when splitview is active. - static constexpr float kFlingToOverviewFromSnappingAreaThreshold = 1000.f; - TabletModeAppWindowDragController(); ~TabletModeAppWindowDragController() override; @@ -48,9 +40,7 @@ void UpdateWindowDrag(ui::GestureEvent* event); void EndWindowDrag(ui::GestureEvent* event, wm::WmToplevelWindowEventHandler::DragResult result); - - // Returns true if fling event should drop the window into overview grid. - bool ShouldFlingIntoOverview(ui::GestureEvent* event); + void FlingOrSwipe(ui::GestureEvent* event); // display::DisplayObserver: void OnDisplayMetricsChanged(const display::Display& display,
diff --git a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.cc b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.cc index 8c16b95..06afd86 100644 --- a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.cc +++ b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_controller.cc
@@ -80,10 +80,7 @@ void TabletModeBrowserWindowDragController::FlingOrSwipe( ui::GestureEvent* event) { - // TODO(xdai): Add special logic for fling events. - drag_delegate_->EndWindowDrag( - wm::WmToplevelWindowEventHandler::DragResult::SUCCESS, - previous_location_in_screen_); + drag_delegate_->FlingOrSwipe(event); } } // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc index f168d093..66b42bfc 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
@@ -216,6 +216,24 @@ did_move_ = false; } +void TabletModeWindowDragDelegate::FlingOrSwipe(ui::GestureEvent* event) { + if (ShouldFlingIntoOverview(event)) { + DCHECK(Shell::Get()->window_selector_controller()->IsSelecting()); + Shell::Get()->window_selector_controller()->window_selector()->AddItem( + dragged_window_, /*reposition=*/true, /*animate=*/false); + } + EndWindowDrag(wm::WmToplevelWindowEventHandler::DragResult::SUCCESS, + GetEventLocationInScreen(event)); +} + +gfx::Point TabletModeWindowDragDelegate::GetEventLocationInScreen( + const ui::GestureEvent* event) const { + gfx::Point location_in_screen(event->location()); + ::wm::ConvertPointToScreen(static_cast<aura::Window*>(event->target()), + &location_in_screen); + return location_in_screen; +} + IndicatorState TabletModeWindowDragDelegate::GetIndicatorState( const gfx::Point& location_in_screen) const { SplitViewController::SnapPosition snap_position = @@ -353,4 +371,49 @@ SetTransform(dragged_window_, transform); } +bool TabletModeWindowDragDelegate::ShouldFlingIntoOverview( + const ui::GestureEvent* event) const { + if (event->type() != ui::ET_SCROLL_FLING_START) + return false; + + const gfx::Point location_in_screen = GetEventLocationInScreen(event); + const IndicatorState indicator_state = GetIndicatorState(location_in_screen); + const bool is_landscape = + split_view_controller_->IsCurrentScreenOrientationLandscape(); + const float velocity = is_landscape ? event->details().velocity_x() + : event->details().velocity_y(); + + // Drop the window into overview if fling with large enough velocity to the + // opposite snap position when preview area is shown. + if (split_view_controller_->IsCurrentScreenOrientationPrimary()) { + if (indicator_state == IndicatorState::kPreviewAreaLeft) + return velocity > kFlingToOverviewFromSnappingAreaThreshold; + else if (indicator_state == IndicatorState::kPreviewAreaRight) + return -velocity > kFlingToOverviewFromSnappingAreaThreshold; + } else { + if (indicator_state == IndicatorState::kPreviewAreaLeft) + return -velocity > kFlingToOverviewFromSnappingAreaThreshold; + else if (indicator_state == IndicatorState::kPreviewAreaRight) + return velocity > kFlingToOverviewFromSnappingAreaThreshold; + } + + const SplitViewController::State snap_state = split_view_controller_->state(); + const int end_position = + is_landscape ? location_in_screen.x() : location_in_screen.y(); + // Fling the window when splitview is active. Since each snapping area in + // splitview has a corresponding snap position. Fling the window to the + // opposite position of the area's snap position with large enough velocity + // should drop the window into overview grid. + if (snap_state == SplitViewController::LEFT_SNAPPED || + snap_state == SplitViewController::RIGHT_SNAPPED) { + return end_position > split_view_controller_->divider_position() + ? -velocity > kFlingToOverviewFromSnappingAreaThreshold + : velocity > kFlingToOverviewFromSnappingAreaThreshold; + } + + // Consider only the velocity_y if splitview is not active and preview area is + // not shown. + return event->details().velocity_y() > kFlingToOverviewThreshold; +} + } // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h index 44e27b8f4..4369b81 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h +++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h
@@ -30,6 +30,14 @@ // into overview. static constexpr float kDragPositionToOverviewRatio = 0.5f; + // Threshold of the fling velocity to drop the dragged window into overview if + // fling from the top of the display or from the caption area of the window. + static constexpr float kFlingToOverviewThreshold = 2000.f; + + // Threshold of the fling velocity to drop the dragged window into overview if + // fling inside preview area or when splitview is active. + static constexpr float kFlingToOverviewFromSnappingAreaThreshold = 1000.f; + enum class UpdateDraggedWindowType { UPDATE_BOUNDS, UPDATE_TRANSFORM, @@ -54,6 +62,12 @@ void EndWindowDrag(wm::WmToplevelWindowEventHandler::DragResult result, const gfx::Point& location_in_screen); + // Calls when a window ends dragging because of fling or swipe. + void FlingOrSwipe(ui::GestureEvent* event); + + // Return the location of |event| in screen coordinates. + gfx::Point GetEventLocationInScreen(const ui::GestureEvent* event) const; + // Returns the IndicatorState according to |location_in_screen|. IndicatorState GetIndicatorState(const gfx::Point& location_in_screen) const; @@ -95,6 +109,9 @@ SplitViewController::SnapPosition snap_position, int end_y_position_in_screen) const; + // Returns true if fling event should drop the window into overview grid. + bool ShouldFlingIntoOverview(const ui::GestureEvent* event) const; + SplitViewController* const split_view_controller_; // A widget to display the drag indicators and preview window.
diff --git a/ash/wm/tablet_mode/tablet_mode_window_state.cc b/ash/wm/tablet_mode/tablet_mode_window_state.cc index 5998d3ad..a3153f5 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_state.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_state.cc
@@ -7,6 +7,7 @@ #include <utility> #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_animation_types.h" #include "ash/public/cpp/window_properties.h" #include "ash/public/cpp/window_state_type.h" #include "ash/screen_util.h" @@ -15,7 +16,6 @@ #include "ash/wm/screen_pinning_controller.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_window_manager.h" -#include "ash/wm/window_animation_types.h" #include "ash/wm/window_properties.h" #include "ash/wm/window_state_util.h" #include "ash/wm/window_util.h"
diff --git a/ash/wm/window_animations.cc b/ash/wm/window_animations.cc index 232a16e..7f6defd 100644 --- a/ash/wm/window_animations.cc +++ b/ash/wm/window_animations.cc
@@ -10,8 +10,11 @@ #include <utility> #include <vector> +#include "ash/app_list/app_list_controller_impl.h" +#include "ash/app_list/home_launcher_gesture_handler.h" +#include "ash/public/cpp/window_animation_types.h" #include "ash/shelf/shelf.h" -#include "ash/wm/window_animation_types.h" +#include "ash/shell.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace_controller.h" #include "base/i18n/rtl.h" @@ -228,6 +231,38 @@ AnimateShowHideWindowCommon_BrightnessGrayscale(window, false); } +void AnimateShowWindow_SlideDown(aura::Window* window) { + AppListControllerImpl* app_list_controller = + Shell::Get()->app_list_controller(); + + if (app_list_controller && + app_list_controller->IsHomeLauncherEnabledInTabletMode()) { + // Slide down the window from above screen to show and, meanwhile, slide + // down the home launcher off screen. + HomeLauncherGestureHandler* handler = + app_list_controller->home_launcher_gesture_handler(); + if (handler && + handler->HideHomeLauncherForWindow( + display::Screen::GetScreen()->GetDisplayNearestView(window), + window)) { + // Now that the window has been restored, we need to clear its animation + // style to default so that normal animation applies. + ::wm::SetWindowVisibilityAnimationType( + window, ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); + return; + } + } + + // Fallback to use minimize animation. + AnimateShowWindow_Minimize(window); +} + +void AnimateHideWindow_SlideDown(aura::Window* window) { + // The hide animation should be handled in HomeLauncherGestureHandler, so + // fallback to use minimize animation here. + AnimateHideWindow_Minimize(window); +} + bool AnimateShowWindow(aura::Window* window) { if (!::wm::HasWindowVisibilityAnimationTransition(window, ::wm::ANIMATE_SHOW)) { @@ -241,6 +276,9 @@ case wm::WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE: AnimateShowWindow_BrightnessGrayscale(window); return true; + case wm::WINDOW_VISIBILITY_ANIMATION_TYPE_SLIDE_DOWN: + AnimateShowWindow_SlideDown(window); + return true; default: NOTREACHED(); return false; @@ -260,6 +298,9 @@ case wm::WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE: AnimateHideWindow_BrightnessGrayscale(window); return true; + case wm::WINDOW_VISIBILITY_ANIMATION_TYPE_SLIDE_DOWN: + AnimateHideWindow_SlideDown(window); + return true; default: NOTREACHED(); return false;
diff --git a/ash/wm/window_animations_unittest.cc b/ash/wm/window_animations_unittest.cc index 212de69..5617b9b 100644 --- a/ash/wm/window_animations_unittest.cc +++ b/ash/wm/window_animations_unittest.cc
@@ -5,8 +5,8 @@ #include "ash/wm/window_animations.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_animation_types.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_animation_types.h" #include "ash/wm/window_state.h" #include "ash/wm/workspace_controller.h" #include "base/time/time.h"
diff --git a/base/containers/README.md b/base/containers/README.md index e5218815..e788262b 100644 --- a/base/containers/README.md +++ b/base/containers/README.md
@@ -65,7 +65,7 @@ | `base::flat_map`, `base::flat_set` | 24 bytes | 0 (see notes) | No | | `base::small_map` | 24 bytes (see notes) | 32 bytes | No | -**Takeaways:** `std::unordered_map` and `std::unordered_map` have high +**Takeaways:** `std::unordered_map` and `std::unordered_set` have high overhead for small container sizes, so prefer these only for larger workloads. Code size comparisons for a block of code (see appendix) on Windows using
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h index a4549e1..86de4d83 100644 --- a/base/mac/sdk_forward_declarations.h +++ b/base/mac/sdk_forward_declarations.h
@@ -360,10 +360,4 @@ // ---------------------------------------------------------------------------- BASE_EXPORT extern "C" NSString* const kCWSSIDDidChangeNotification; -// Once Chrome is built with at least the macOS 10.13 SDK, everything within -// this preprocessor block can be removed. -#if !defined(MAC_OS_X_VERSION_10_13) -typedef NSString* NSTextCheckingOptionKey; -#endif - #endif // BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
diff --git a/base/macros.h b/base/macros.h index 3064a1b5..96067008 100644 --- a/base/macros.h +++ b/base/macros.h
@@ -82,6 +82,9 @@ // static base::NoDestructor<Factory> instance; // return *instance; // } +// +// Removal of this macro is tracked in https://crbug.com/893317. +// // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \ static type& name = *new type arguments
diff --git a/base/sys_info_posix.cc b/base/sys_info_posix.cc index 32db410..f720f65 100644 --- a/base/sys_info_posix.cc +++ b/base/sys_info_posix.cc
@@ -178,7 +178,7 @@ } #endif -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !(OS_CHROMEOS) +#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS) // static std::string SysInfo::OperatingSystemVersion() { struct utsname info;
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 1226030..d485837 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -89d8d1c05501a15b2b023f01966c0a47e67e385f \ No newline at end of file +b94593097edc8946187a1222783e0060a67f512d \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index ade366f7..82725a6 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -59e5c6849d5f25d893424e1ec1e12326a50eded0 \ No newline at end of file +6ed08743105154bd5427e21c867b5f0f1dfb28a1 \ No newline at end of file
diff --git a/cc/input/scroll_snap_data.h b/cc/input/scroll_snap_data.h index e44b9d8..c18f737 100644 --- a/cc/input/scroll_snap_data.h +++ b/cc/input/scroll_snap_data.h
@@ -63,26 +63,26 @@ struct ScrollSnapAlign { ScrollSnapAlign() - : alignment_inline(SnapAlignment::kNone), - alignment_block(SnapAlignment::kNone) {} + : alignment_block(SnapAlignment::kNone), + alignment_inline(SnapAlignment::kNone) {} explicit ScrollSnapAlign(SnapAlignment alignment) - : alignment_inline(alignment), alignment_block(alignment) {} + : alignment_block(alignment), alignment_inline(alignment) {} - ScrollSnapAlign(SnapAlignment i, SnapAlignment b) - : alignment_inline(i), alignment_block(b) {} + ScrollSnapAlign(SnapAlignment b, SnapAlignment i) + : alignment_block(b), alignment_inline(i) {} bool operator==(const ScrollSnapAlign& other) const { - return alignment_inline == other.alignment_inline && - alignment_block == other.alignment_block; + return alignment_block == other.alignment_block && + alignment_inline == other.alignment_inline; } bool operator!=(const ScrollSnapAlign& other) const { return !(*this == other); } - SnapAlignment alignment_inline; SnapAlignment alignment_block; + SnapAlignment alignment_inline; }; // We should really use gfx::RangeF. However, it includes windows.h which would
diff --git a/cc/input/scroll_snap_data_unittest.cc b/cc/input/scroll_snap_data_unittest.cc index a688448..d2347148 100644 --- a/cc/input/scroll_snap_data_unittest.cc +++ b/cc/input/scroll_snap_data_unittest.cc
@@ -59,7 +59,7 @@ SnapContainerData container( ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(100, 100)); - SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kEnd), + SnapAreaData area(ScrollSnapAlign(SnapAlignment::kEnd, SnapAlignment::kStart), gfx::RectF(200, 0, 100, 100), false); container.AddSnapAreaData(area); gfx::ScrollOffset current_position(50, 50); @@ -78,10 +78,10 @@ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); SnapAreaData snap_x_only( - ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), + ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), gfx::RectF(80, 0, 150, 150), false); SnapAreaData snap_y_only( - ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), + ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), gfx::RectF(0, 70, 150, 150), false); SnapAreaData snap_on_both(ScrollSnapAlign(SnapAlignment::kStart), gfx::RectF(50, 150, 150, 150), false); @@ -101,10 +101,10 @@ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); SnapAreaData snap_x_only( - ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), + ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), gfx::RectF(80, 0, 150, 150), false); SnapAreaData snap_y_only( - ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), + ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), gfx::RectF(0, 70, 150, 150), false); SnapAreaData snap_on_both(ScrollSnapAlign(SnapAlignment::kStart), gfx::RectF(50, 150, 150, 150), false); @@ -124,10 +124,10 @@ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); SnapAreaData snap_x_only( - ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), + ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), gfx::RectF(80, 0, 150, 150), false); SnapAreaData snap_y_only( - ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), + ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), gfx::RectF(0, 70, 150, 150), false); gfx::ScrollOffset current_position(100, 100); container.AddSnapAreaData(snap_x_only); @@ -144,10 +144,10 @@ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800)); SnapAreaData snap_x_only( - ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), + ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), gfx::RectF(300, 400, 100, 100), false); SnapAreaData snap_y_only( - ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), + ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), gfx::RectF(400, 300, 100, 100), false); gfx::ScrollOffset current_position(0, 0); container.AddSnapAreaData(snap_x_only); @@ -169,13 +169,13 @@ // After that, we look for another snap point on y axis which does not // conflict with the snap point on x. SnapAreaData snap_x( - ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), + ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), gfx::RectF(150, 0, 100, 100), false); SnapAreaData snap_y1( - ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), + ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), gfx::RectF(0, 180, 100, 100), false); SnapAreaData snap_y2( - ScrollSnapAlign(SnapAlignment::kNone, SnapAlignment::kStart), + ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone), gfx::RectF(250, 80, 100, 100), false); container.AddSnapAreaData(snap_x); container.AddSnapAreaData(snap_y1);
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index fc1451b..1ef88c7c 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc
@@ -871,6 +871,12 @@ void Layer::UpdateScrollOffset(const gfx::ScrollOffset& scroll_offset) { DCHECK(scrollable()); + + // This function updates the property tree scroll offsets but in layer list + // mode this should occur during the main -> cc property tree push. + if (layer_tree_host_->IsUsingLayerLists()) + return; + if (scroll_tree_index() == ScrollTree::kInvalidNodeId) { // Ensure the property trees just have not been built yet but are marked for // being built which will set the correct scroll offset values.
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index 93725588..020bcee 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -727,10 +727,10 @@ 1.f - layer_tree_impl()->CurrentBrowserControlsShownRatio(); viewport_rect_for_tile_priority_in_content_space_.Inset( - 0, // left - 0, // top, - 0, // right, - std::ceilf(-total_controls_height * hidden_ratio)); // bottom + 0, // left + 0, // top, + 0, // right, + std::ceil(-total_controls_height * hidden_ratio)); // bottom } } }
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index 283e364..fc2282c5 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -433,14 +433,8 @@ void UpdateLayerTreeHost() override { test_hooks_->UpdateLayerTreeHost(); } - void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) override { - test_hooks_->ApplyViewportDeltas(inner_delta, outer_delta, - elastic_overscroll_delta, page_scale, - top_controls_delta); + void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { + test_hooks_->ApplyViewportChanges(args); } void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel,
diff --git a/cc/test/stub_layer_tree_host_client.h b/cc/test/stub_layer_tree_host_client.h index fa24c0fa..bb4078f73 100644 --- a/cc/test/stub_layer_tree_host_client.h +++ b/cc/test/stub_layer_tree_host_client.h
@@ -21,11 +21,7 @@ void BeginMainFrameNotExpectedSoon() override {} void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override {} void UpdateLayerTreeHost() override {} - void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) override {} + void ApplyViewportChanges(const ApplyViewportChangesArgs&) override {} void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel, bool has_scrolled_by_touch) override {} void RequestNewLayerTreeFrameSink() override {}
diff --git a/cc/test/test_hooks.h b/cc/test/test_hooks.h index 48262161..a5a0ca5 100644 --- a/cc/test/test_hooks.h +++ b/cc/test/test_hooks.h
@@ -21,6 +21,8 @@ namespace cc { +struct ApplyViewportChangesArgs; + // Used by test stubs to notify the test when something interesting happens. class TestHooks : public AnimationDelegate { public: @@ -95,12 +97,7 @@ virtual void DisplayDidDrawAndSwapOnThread() {} // Main thread hooks. - virtual void ApplyViewportDeltas( - const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float scale, - float top_controls_delta) {} + virtual void ApplyViewportChanges(const ApplyViewportChangesArgs& args) {} virtual void BeginMainFrameNotExpectedSoon() {} virtual void BeginMainFrame(const viz::BeginFrameArgs& args) {} virtual void WillBeginMainFrame() {}
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index e3bd5b6d..ecee592 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -893,9 +893,9 @@ info.elastic_overscroll_delta); // TODO(ccameron): pass the elastic overscroll here so that input events // may be translated appropriately. - client_->ApplyViewportDeltas(inner_viewport_scroll_delta, gfx::Vector2dF(), - info.elastic_overscroll_delta, - info.page_scale_delta, info.top_controls_delta); + client_->ApplyViewportChanges( + {inner_viewport_scroll_delta, info.elastic_overscroll_delta, + info.page_scale_delta, info.top_controls_delta}); SetNeedsUpdateLayers(); }
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h index 302521d..9715043 100644 --- a/cc/trees/layer_tree_host_client.h +++ b/cc/trees/layer_tree_host_client.h
@@ -9,6 +9,7 @@ #include "base/memory/ref_counted.h" #include "base/time/time.h" +#include "ui/gfx/geometry/vector2d_f.h" namespace gfx { struct PresentationFeedback; @@ -21,6 +22,23 @@ namespace cc { +struct ApplyViewportChangesArgs { + // Scroll offset delta of the inner (visual) viewport. + gfx::Vector2dF inner_delta; + + // Elastic overscroll effect offset delta. This is used only on Mac. a.k.a + // "rubber-banding" overscroll. + gfx::Vector2dF elastic_overscroll_delta; + + // "Pinch-zoom" page scale delta. This is a multiplicative delta. i.e. + // main_thread_scale * delta == impl_thread_scale. + float page_scale_delta; + + // How much the browser controls have been shown or hidden. The ratio runs + // between 0 (hidden) and 1 (full-shown). This is additive. + float browser_controls_delta; +}; + // A LayerTreeHost is bound to a LayerTreeHostClient. The main rendering // loop (in ProxyMain or SingleThreadProxy) calls methods on the // LayerTreeHost, which then handles them and also calls into the equivalent @@ -65,12 +83,11 @@ // mutations on the LayerTreeHost.) virtual void UpdateLayerTreeHost() = 0; - virtual void ApplyViewportDeltas( - const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) = 0; + // Notifies the client of viewport-related changes that occured in the + // LayerTreeHost since the last commit. This typically includes things + // related to pinch-zoom, browser controls (aka URL bar), overscroll, etc. + virtual void ApplyViewportChanges(const ApplyViewportChangesArgs& args) = 0; + virtual void RecordWheelAndTouchScrollingCount( bool has_scrolled_by_wheel, bool has_scrolled_by_touch) = 0;
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index fb12cf6..d71fdf9 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -3234,14 +3234,12 @@ void BeginTest() override { PostSetNeedsCommitToMainThread(); } - void ApplyViewportDeltas(const gfx::Vector2dF& scroll_delta, - const gfx::Vector2dF&, - const gfx::Vector2dF& elastic_overscroll_delta, - float scale, - float) override { + void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { gfx::ScrollOffset offset = scroll_layer_->CurrentScrollOffset(); - scroll_layer_->SetScrollOffset(ScrollOffsetWithDelta(offset, scroll_delta)); - layer_tree_host()->SetPageScaleFactorAndLimits(scale, 0.5f, 2.f); + scroll_layer_->SetScrollOffset( + ScrollOffsetWithDelta(offset, args.inner_delta)); + layer_tree_host()->SetPageScaleFactorAndLimits(args.page_scale_delta, 0.5f, + 2.f); } void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { @@ -3323,14 +3321,10 @@ } } - void ApplyViewportDeltas(const gfx::Vector2dF& inner, - const gfx::Vector2dF& outer, - const gfx::Vector2dF& elastic_overscroll_delta, - float scale_delta, - float top_controls_delta) override { + void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { EXPECT_TRUE(sent_gesture_); - EXPECT_EQ(gfx::Vector2dF(50, 50), inner); - EXPECT_EQ(2, scale_delta); + EXPECT_EQ(gfx::Vector2dF(50, 50), args.inner_delta); + EXPECT_EQ(2, args.page_scale_delta); auto* scroll_layer = layer_tree_host()->inner_viewport_scroll_layer(); EXPECT_EQ(gfx::ScrollOffset(50, 50), scroll_layer->CurrentScrollOffset()); @@ -7022,13 +7016,9 @@ EndTest(); } - void ApplyViewportDeltas(const gfx::Vector2dF& inner, - const gfx::Vector2dF& outer, - const gfx::Vector2dF& elastic_overscroll_delta, - float scale_delta, - float top_controls_delta) override { - EXPECT_EQ(info_.page_scale_delta, scale_delta); - EXPECT_EQ(info_.top_controls_delta, top_controls_delta); + void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { + EXPECT_EQ(info_.page_scale_delta, args.page_scale_delta); + EXPECT_EQ(info_.top_controls_delta, args.browser_controls_delta); deltas_sent_to_client_ = true; }
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc index 8f5ff61..cef1be49 100644 --- a/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -1852,18 +1852,14 @@ DCHECK(scroll_elasticity_helper_); } - void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float scale, - float top_controls_delta) override { + void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { DCHECK_NE(0, num_begin_main_frames_main_thread_) << "The first BeginMainFrame has no deltas to report"; DCHECK_LT(num_begin_main_frames_main_thread_, 5); gfx::Vector2dF expected_elastic_overscroll = elastic_overscroll_test_cases_[num_begin_main_frames_main_thread_]; - current_elastic_overscroll_ += elastic_overscroll_delta; + current_elastic_overscroll_ += args.elastic_overscroll_delta; EXPECT_EQ(expected_elastic_overscroll, current_elastic_overscroll_); EXPECT_EQ(expected_elastic_overscroll, layer_tree_host()->elastic_overscroll());
diff --git a/chrome/VERSION b/chrome/VERSION index 071c697..3f52625 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=71 MINOR=0 -BUILD=3574 +BUILD=3575 PATCH=0
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java index 218389c..36038f0 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java
@@ -9,6 +9,7 @@ import com.google.android.libraries.feed.api.common.ThreadUtils; import com.google.android.libraries.feed.api.scope.FeedProcessScope; import com.google.android.libraries.feed.feedapplifecyclelistener.FeedAppLifecycleListener; +import com.google.android.libraries.feed.host.config.ApplicationInfo; import com.google.android.libraries.feed.host.config.Configuration; import com.google.android.libraries.feed.host.config.DebugBehavior; import com.google.android.libraries.feed.host.network.NetworkClient; @@ -97,19 +98,23 @@ sFeedScheduler = schedulerBridge; FeedAppLifecycleListener lifecycleListener = new FeedAppLifecycleListener(new ThreadUtils()); + // TODO(gangwu): Getting real build info if possible. + ApplicationInfo applicationInfo = + new ApplicationInfo.Builder(ContextUtils.getApplicationContext()) + .setAppType(ApplicationInfo.AppType.CHROME) + .build(); FeedContentStorage contentStorage = new FeedContentStorage(profile); FeedJournalStorage journalStorage = new FeedJournalStorage(profile); NetworkClient networkClient = sTestNetworkClient == null ? new FeedNetworkBridge(profile) : sTestNetworkClient; - sFeedProcessScope = - new FeedProcessScope - .Builder(configHostApi, Executors.newSingleThreadExecutor(), - new LoggingApiImpl(), networkClient, - schedulerBridge, lifecycleListener, DebugBehavior.SILENT, - ContextUtils.getApplicationContext()) - .setContentStorage(contentStorage) - .setJournalStorage(journalStorage) - .build(); + sFeedProcessScope = new FeedProcessScope + .Builder(configHostApi, Executors.newSingleThreadExecutor(), + new LoggingApiImpl(), networkClient, schedulerBridge, + lifecycleListener, DebugBehavior.SILENT, + ContextUtils.getApplicationContext(), applicationInfo) + .setContentStorage(contentStorage) + .setJournalStorage(journalStorage) + .build(); schedulerBridge.initializeFeedDependencies( sFeedProcessScope.getRequestManager(), sFeedProcessScope.getSessionManager()); @@ -134,11 +139,14 @@ FeedAppLifecycle feedAppLifecycle, FeedAppLifecycleListener lifecycleListener) { Configuration configHostApi = FeedConfiguration.createConfiguration(); sFeedScheduler = feedScheduler; + ApplicationInfo applicationInfo = + new ApplicationInfo.Builder(ContextUtils.getApplicationContext()).build(); + sFeedProcessScope = new FeedProcessScope .Builder(configHostApi, Executors.newSingleThreadExecutor(), new LoggingApiImpl(), networkClient, sFeedScheduler, lifecycleListener, DebugBehavior.SILENT, - ContextUtils.getApplicationContext()) + ContextUtils.getApplicationContext(), applicationInfo) .build(); sFeedOfflineIndicator = feedOfflineIndicator; sFeedAppLifecycle = feedAppLifecycle;
diff --git a/chrome/android/java/res/layout/icon_row_menu_footer.xml b/chrome/android/java/res/layout/icon_row_menu_footer.xml index 9b18e375..d8d9967dd 100644 --- a/chrome/android/java/res/layout/icon_row_menu_footer.xml +++ b/chrome/android/java/res/layout/icon_row_menu_footer.xml
@@ -6,6 +6,7 @@ --> <org.chromium.chrome.browser.appmenu.AppMenuIconRowFooter xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > @@ -42,10 +43,11 @@ android:src="@drawable/btn_info" android:contentDescription="@string/accessibility_menu_info" /> + <!-- The src will be set in onFinishInflate. --> <android.support.v7.widget.AppCompatImageButton android:id="@+id/reload_menu_id" style="@style/OverflowMenuButton" - android:src="@drawable/btn_reload_stop" - android:contentDescription="@string/accessibility_btn_refresh" /> + android:contentDescription="@string/accessibility_btn_refresh" + tools:src="@drawable/btn_reload_stop" /> </LinearLayout> </org.chromium.chrome.browser.appmenu.AppMenuIconRowFooter>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 997b5a8..7f5450c 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -539,7 +539,6 @@ <dimen name="download_manager_prefetch_horizontal_margin">16dp</dimen> <dimen name="download_manager_prefetch_vertical_margin">12dp</dimen> <dimen name="download_manager_section_title_padding_top">16dp</dimen> - <dimen name="download_manager_section_title_padding_top_condensed">0dp</dimen> <dimen name="download_manager_section_title_padding_bottom">0dp</dimen> <dimen name="download_manager_section_title_padding_image">8dp</dimen> <!-- The corner radius is calculated by subtracting the hairline border width from the
diff --git a/chrome/android/java/res_download/layout/download_manager_date_item.xml b/chrome/android/java/res_download/layout/download_manager_date_item.xml deleted file mode 100644 index 7069da5..0000000 --- a/chrome/android/java/res_download/layout/download_manager_date_item.xml +++ /dev/null
@@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2018 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. ---> - -<TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingTop="@dimen/download_manager_section_title_padding_top" - android:paddingBottom="@dimen/download_manager_section_title_padding_bottom" - android:paddingStart="@dimen/list_item_default_margin" - android:maxLines="1" - android:gravity="start|center_vertical" - android:textAppearance="@style/BlackTitle1" - android:textAlignment="viewStart" /> \ No newline at end of file
diff --git a/chrome/android/java/res_download/layout/download_manager_section_header.xml b/chrome/android/java/res_download/layout/download_manager_section_header.xml index a914005..086cdac5 100644 --- a/chrome/android/java/res_download/layout/download_manager_section_header.xml +++ b/chrome/android/java/res_download/layout/download_manager_section_header.xml
@@ -4,28 +4,45 @@ found in the LICENSE file. --> -<LinearLayout +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal"> + android:layout_height="wrap_content"> + + <Space + android:id="@+id/top_space" + android:layout_width="match_parent" + android:layout_height="@dimen/download_manager_section_title_padding_top" /> + + <TextView + android:id="@+id/date" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/top_space" + android:paddingStart="@dimen/list_item_default_margin" + android:maxLines="1" + android:textAppearance="@style/BlackTitle1"/> <TextView android:id="@+id/title" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" - android:paddingTop="@dimen/download_manager_section_title_padding_top" - android:paddingBottom="@dimen/download_manager_section_title_padding_bottom" - android:paddingStart="@dimen/list_item_default_margin" - android:textAppearance="@style/BlackHint2" - android:textAlignment="viewStart"/> - - <include layout="@layout/list_menu_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" /> + android:layout_below="@+id/date" + android:paddingStart="@dimen/list_item_default_margin" + android:textAppearance="@style/BlackHint2" + android:maxLines="1" /> -</LinearLayout> + <Space + android:id="@+id/bottom_space" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_below="@+id/title" /> + + <include layout="@layout/list_menu_button" + android:layout_width="48dp" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" /> + +</RelativeLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java index 4000e47..a20e9b8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java
@@ -5,6 +5,8 @@ package org.chromium.chrome.browser.appmenu; import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v7.content.res.AppCompatResources; import android.support.v7.widget.AppCompatImageButton; import android.util.AttributeSet; @@ -53,6 +55,13 @@ mReloadButton = (AppCompatImageButton) findViewById(R.id.reload_menu_id); mReloadButton.setOnClickListener(this); + + // ImageView tinting doesn't work with LevelListDrawable, use Drawable tinting instead. + // See https://crbug.com/891593 for details. + Drawable icon = AppCompatResources.getDrawable(getContext(), R.drawable.btn_reload_stop); + DrawableCompat.setTintList( + icon, AppCompatResources.getColorStateList(getContext(), R.color.dark_mode_tint)); + mReloadButton.setImageDrawable(icon); } /** @@ -74,7 +83,6 @@ mDownloadButton.setEnabled(DownloadUtils.isAllowedToDownloadPage(currentTab)); - mReloadButton.setImageResource(R.drawable.btn_reload_stop); loadingStateChanged(currentTab.isLoading()); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java index efb7742..d6d1eaf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java
@@ -8,7 +8,6 @@ import org.chromium.chrome.browser.download.home.filter.Filters; import org.chromium.chrome.browser.download.home.filter.OfflineItemFilterObserver; import org.chromium.chrome.browser.download.home.filter.OfflineItemFilterSource; -import org.chromium.chrome.browser.download.home.list.ListItem.DateListItem; import org.chromium.chrome.browser.download.home.list.ListItem.OfflineItemListItem; import org.chromium.chrome.browser.download.home.list.ListItem.SectionHeaderListItem; import org.chromium.chrome.browser.download.home.list.ListItem.SeparatorViewListItem; @@ -146,21 +145,18 @@ DateGroup dateGroup = mDateGroups.get(date); int sectionIndex = 0; - // Add an item for the date header. - if (!mHideAllHeaders) { - listItems.add(new DateListItem(CalendarUtils.getStartOfDay(date.getTime()))); - } - // For each section. for (Integer filter : dateGroup.sections.keySet()) { Section section = dateGroup.sections.get(filter); // Add a section header. - if (!mHideSectionHeaders && !mHideAllHeaders) { + if (!mHideAllHeaders) { SectionHeaderListItem sectionHeaderItem = new SectionHeaderListItem(filter, date.getTime()); + sectionHeaderItem.showDate = sectionIndex == 0; + sectionHeaderItem.showTitle = !mHideSectionHeaders; + sectionHeaderItem.showMenu = filter == OfflineItemFilter.FILTER_IMAGE; sectionHeaderItem.items = new ArrayList<>(section.items.values()); - sectionHeaderItem.isFirstSectionOfDay = sectionIndex == 0; listItems.add(sectionHeaderItem); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java index e43c6fdd..78191a7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java
@@ -21,6 +21,7 @@ import org.chromium.chrome.browser.modelutil.ForwardingListObservable; import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor; import org.chromium.chrome.browser.modelutil.RecyclerViewAdapter; +import org.chromium.chrome.browser.modelutil.RecyclerViewAdapter.Delegate; /** * The View component of a DateOrderedList. This takes the DateOrderedListModel and creates the @@ -60,6 +61,11 @@ ListItemViewHolder viewHolder, int position, @Nullable Void payload) { viewHolder.bind(mModel.getProperties(), mModel.get(position)); } + + @Override + public void onViewRecycled(ListItemViewHolder viewHolder) { + viewHolder.recycle(); + } } /** Creates an instance of a {@link DateOrderedListView} representing {@code model}. */ @@ -128,6 +134,11 @@ super.onLayoutChildren(recycler, state); } + @Override + public boolean supportsPredictiveItemAnimations() { + return false; + } + private class SpanSizeLookupImpl extends SpanSizeLookup { // SpanSizeLookup implementation. @Override @@ -156,7 +167,8 @@ case ListUtils.ViewType.IN_PROGRESS_VIDEO: outRect.left = mPrefetchHorizontalPaddingPx; outRect.right = mPrefetchHorizontalPaddingPx; - outRect.bottom = mPrefetchHorizontalPaddingPx; + outRect.top = mPrefetchVerticalPaddingPx / 2; + outRect.bottom = mPrefetchVerticalPaddingPx / 2; break; case ListUtils.ViewType.PREFETCH: outRect.left = mPrefetchHorizontalPaddingPx;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java index e79c150..11ee72f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItem.java
@@ -44,7 +44,7 @@ } /** A {@link ListItem} that involves a {@link Date}. */ - public static class DateListItem extends ListItem { + private abstract static class DateListItem extends ListItem { public final Date date; /** @@ -74,7 +74,9 @@ /** A {@link ListItem} representing a section header. */ public static class SectionHeaderListItem extends DateListItem { public final int filter; - public boolean isFirstSectionOfDay; + public boolean showDate; + public boolean showTitle; + public boolean showMenu; public List<OfflineItem> items; /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java index 4ba2d164..e7a7c864 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java
@@ -8,7 +8,6 @@ import android.support.annotation.StringRes; import org.chromium.chrome.R; -import org.chromium.chrome.browser.download.home.list.ListItem.DateListItem; import org.chromium.chrome.browser.download.home.list.ListItem.OfflineItemListItem; import org.chromium.chrome.browser.download.home.list.ListItem.ViewListItem; import org.chromium.components.offline_items_collection.OfflineItem; @@ -70,32 +69,28 @@ return separator.isDateDivider() ? ViewType.SEPARATOR_DATE : ViewType.SEPARATOR_SECTION; } - if (item instanceof DateListItem) { - if (item instanceof OfflineItemListItem) { - OfflineItemListItem offlineItem = (OfflineItemListItem) item; + if (item instanceof OfflineItemListItem) { + OfflineItemListItem offlineItem = (OfflineItemListItem) item; - if (offlineItem.item.isSuggested) return ViewType.PREFETCH; + if (offlineItem.item.isSuggested) return ViewType.PREFETCH; - boolean inProgress = offlineItem.item.state == OfflineItemState.IN_PROGRESS - || offlineItem.item.state == OfflineItemState.PAUSED - || offlineItem.item.state == OfflineItemState.INTERRUPTED - || offlineItem.item.state == OfflineItemState.PENDING - || offlineItem.item.state == OfflineItemState.FAILED; + boolean inProgress = offlineItem.item.state == OfflineItemState.IN_PROGRESS + || offlineItem.item.state == OfflineItemState.PAUSED + || offlineItem.item.state == OfflineItemState.INTERRUPTED + || offlineItem.item.state == OfflineItemState.PENDING + || offlineItem.item.state == OfflineItemState.FAILED; - switch (offlineItem.item.filter) { - case OfflineItemFilter.FILTER_VIDEO: - return inProgress ? ViewType.IN_PROGRESS_VIDEO : ViewType.VIDEO; - case OfflineItemFilter.FILTER_IMAGE: - return inProgress ? ViewType.IN_PROGRESS_IMAGE : ViewType.IMAGE; - // case OfflineItemFilter.FILTER_PAGE: - // case OfflineItemFilter.FILTER_AUDIO: - // case OfflineItemFilter.FILTER_OTHER: - // case OfflineItemFilter.FILTER_DOCUMENT: - default: - return inProgress ? ViewType.IN_PROGRESS : ViewType.GENERIC; - } - } else { - return ViewType.DATE; + switch (offlineItem.item.filter) { + case OfflineItemFilter.FILTER_VIDEO: + return inProgress ? ViewType.IN_PROGRESS_VIDEO : ViewType.VIDEO; + case OfflineItemFilter.FILTER_IMAGE: + return inProgress ? ViewType.IN_PROGRESS_IMAGE : ViewType.IMAGE; + // case OfflineItemFilter.FILTER_PAGE: + // case OfflineItemFilter.FILTER_AUDIO: + // case OfflineItemFilter.FILTER_OTHER: + // case OfflineItemFilter.FILTER_DOCUMENT: + default: + return inProgress ? ViewType.IN_PROGRESS : ViewType.GENERIC; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/DateViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/DateViewHolder.java deleted file mode 100644 index 308c1d8..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/DateViewHolder.java +++ /dev/null
@@ -1,37 +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. - -package org.chromium.chrome.browser.download.home.list.holder; - -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import org.chromium.chrome.browser.download.home.list.ListItem; -import org.chromium.chrome.browser.download.home.list.UiUtils; -import org.chromium.chrome.browser.modelutil.PropertyModel; -import org.chromium.chrome.download.R; - -/** A {@link RecyclerView.ViewHolder} specifically meant to display a date header. */ -public class DateViewHolder extends ListItemViewHolder { - /** Creates a new {@link DateViewHolder} instance. */ - public static org.chromium.chrome.browser.download.home.list.holder.DateViewHolder create( - ViewGroup parent) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.download_manager_date_item, null); - return new org.chromium.chrome.browser.download.home.list.holder.DateViewHolder(view); - } - - private DateViewHolder(View view) { - super(view); - } - - // ListItemViewHolder implementation. - @Override - public void bind(PropertyModel properties, ListItem item) { - ListItem.DateListItem dateItem = (ListItem.DateListItem) item; - ((TextView) itemView).setText(UiUtils.dateToHeaderString(dateItem.date)); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ListItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ListItemViewHolder.java index f5e41cb..855ba25 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ListItemViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ListItemViewHolder.java
@@ -29,8 +29,6 @@ */ public static ListItemViewHolder create(ViewGroup parent, @ListUtils.ViewType int viewType) { switch (viewType) { - case ListUtils.ViewType.DATE: - return DateViewHolder.create(parent); case ListUtils.ViewType.IN_PROGRESS: return InProgressViewHolder.create(parent); case ListUtils.ViewType.GENERIC: @@ -65,4 +63,10 @@ * @param item The {@link ListItem} to visually represent in this {@link ViewHolder}. */ public abstract void bind(PropertyModel properties, ListItem item); + + /** + * Gives subclasses a chance to free up expensive resources when this {@link ViewHolder} is no + * longer attached to the parent {@link RecyclerView}. + */ + public void recycle() {} }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/OfflineItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/OfflineItemViewHolder.java index 861d1c5..ce172ee7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/OfflineItemViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/OfflineItemViewHolder.java
@@ -95,6 +95,13 @@ } } + @Override + public void recycle() { + // This should cancel any outstanding async request as well as drop any currently visible + // bitmap. + mThumbnail.setImageDrawable(null); + } + /** * Called when a {@link OfflineItemVisuals} are retrieved and are used to build the * {@link Drawable} to use for the thumbnail {@link View}. Can be overridden by subclasses who
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java index e363a23..e9a16e07 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java
@@ -15,11 +15,11 @@ import org.chromium.chrome.browser.download.home.list.ListItem.SectionHeaderListItem; import org.chromium.chrome.browser.download.home.list.ListProperties; import org.chromium.chrome.browser.download.home.list.ListUtils; +import org.chromium.chrome.browser.download.home.list.UiUtils; import org.chromium.chrome.browser.modelutil.PropertyModel; import org.chromium.chrome.browser.widget.ListMenuButton; import org.chromium.chrome.download.R; import org.chromium.components.offline_items_collection.OfflineItem; -import org.chromium.components.offline_items_collection.OfflineItemFilter; import org.chromium.components.offline_items_collection.OfflineItemState; import java.util.ArrayList; @@ -30,8 +30,11 @@ * A {@link ViewHolder} specifically meant to display a section header. */ public class SectionTitleViewHolder extends ListItemViewHolder implements ListMenuButton.Delegate { + private final TextView mDate; private final TextView mTitle; private final ListMenuButton mMore; + private final View mTopSpace; + private final View mBottomSpace; private Runnable mShareCallback; private Runnable mDeleteCallback; @@ -51,8 +54,11 @@ private SectionTitleViewHolder(View view) { super(view); + mDate = (TextView) view.findViewById(R.id.date); mTitle = (TextView) view.findViewById(R.id.title); mMore = (ListMenuButton) view.findViewById(R.id.more); + mTopSpace = view.findViewById(R.id.top_space); + mBottomSpace = view.findViewById(R.id.bottom_space); if (mMore != null) mMore.setDelegate(this); } @@ -62,30 +68,19 @@ SectionHeaderListItem sectionItem = (SectionHeaderListItem) item; mTitle.setText(ListUtils.getTextForSection(sectionItem.filter)); - boolean isPhoto = sectionItem.filter == OfflineItemFilter.FILTER_IMAGE; - Resources resources = itemView.getContext().getResources(); - - int paddingTop = resources.getDimensionPixelSize(isPhoto - ? R.dimen.download_manager_section_title_padding_image - : R.dimen.download_manager_section_title_padding_top); - int paddingBottom = resources.getDimensionPixelSize(isPhoto - ? R.dimen.download_manager_section_title_padding_image - : R.dimen.download_manager_section_title_padding_bottom); - - if (sectionItem.isFirstSectionOfDay) { - paddingTop = resources.getDimensionPixelSize( - R.dimen.download_manager_section_title_padding_top_condensed); + if (sectionItem.showDate) { + mDate.setText(UiUtils.dateToHeaderString(sectionItem.date)); } - mTitle.setPadding( - mTitle.getPaddingLeft(), paddingTop, mTitle.getPaddingRight(), paddingBottom); - - if (mMore != null) mMore.setVisibility(isPhoto ? View.VISIBLE : View.GONE); + updateTopBottomSpacing(sectionItem.showMenu); + mDate.setVisibility(sectionItem.showDate ? View.VISIBLE : View.GONE); + mTitle.setVisibility((sectionItem.showTitle ? View.VISIBLE : View.GONE)); + if (mMore != null) mMore.setVisibility(sectionItem.showMenu ? View.VISIBLE : View.GONE); mHasMultipleItems = sectionItem.items.size() > 1; mCanSelectItems = !getCompletedItems(sectionItem.items).isEmpty(); - if (isPhoto && mMore != null) { + if (sectionItem.showMenu && mMore != null) { assert sectionItem.items.size() > 0; mShareCallback = () -> properties.get(ListProperties.CALLBACK_SHARE) @@ -137,6 +132,22 @@ } } + private void updateTopBottomSpacing(boolean showMenu) { + Resources resources = itemView.getContext().getResources(); + ViewGroup.LayoutParams topSpaceParams = mTopSpace.getLayoutParams(); + ViewGroup.LayoutParams bottomSpaceParams = mBottomSpace.getLayoutParams(); + + topSpaceParams.height = resources.getDimensionPixelSize(showMenu + ? R.dimen.download_manager_section_title_padding_image + : R.dimen.download_manager_section_title_padding_top); + bottomSpaceParams.height = resources.getDimensionPixelSize(showMenu + ? R.dimen.download_manager_section_title_padding_image + : R.dimen.download_manager_section_title_padding_bottom); + + mTopSpace.setLayoutParams(topSpaceParams); + mBottomSpace.setLayoutParams(bottomSpaceParams); + } + private static List<OfflineItem> getCompletedItems(Collection<OfflineItem> items) { List<OfflineItem> completedItems = new ArrayList<>(); for (OfflineItem item : items) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AsyncImageView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AsyncImageView.java index e53e8c7..a14330b9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AsyncImageView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AsyncImageView.java
@@ -85,12 +85,12 @@ */ public void setAsyncImageDrawable(Factory factory, @Nullable Object identifier) { if (mIdentifier != null && identifier != null && mIdentifier.equals(identifier)) return; - mIdentifier = identifier; // This will clear out any outstanding request. setImageDrawable(null); setForegroundDrawableCompat(mWaitingDrawable); + mIdentifier = identifier; mFactory = factory; retrieveDrawableIfNeeded(); } @@ -138,7 +138,7 @@ // If we ended up swapping out the identifier and somehow this request didn't cancel ignore // the response. This does a direct == comparison instead of .equals() because any new // request should have canceled this one (we'll leave null alone though). - if (mIdentifier != identifier) return; + if (mIdentifier != identifier || !mWaitingForResponse) return; mCancelable = null; mWaitingForResponse = false; @@ -149,9 +149,10 @@ private void cancelPreviousDrawableRequest() { mFactory = null; - if (mCancelable != null) { - mCancelable.run(); + if (mWaitingForResponse) { + if (mCancelable != null) mCancelable.run(); mCancelable = null; + mIdentifier = null; mWaitingForResponse = false; } } @@ -160,20 +161,19 @@ // If width or height are not valid, don't start to retrieve the drawable since the // thumbnail may be scaled down to 0. if (getWidth() <= 0 || getHeight() <= 0) return; + if (mFactory == null) return; - if (mFactory != null) { - // Start to retrieve the drawable. - mWaitingForResponse = true; + // Start to retrieve the drawable. + mWaitingForResponse = true; - Object localIdentifier = mIdentifier; - mCancelable = mFactory.get(d - -> setAsyncImageDrawableResponse(d, localIdentifier), - getWidth(), getHeight()); + Object localIdentifier = mIdentifier; + mCancelable = mFactory.get(drawable + -> setAsyncImageDrawableResponse(drawable, localIdentifier), + getWidth(), getHeight()); - // If setAsyncImageDrawableResponse is called synchronously, clear mCancelable. - if (!mWaitingForResponse) mCancelable = null; + // If setAsyncImageDrawableResponse is called synchronously, clear mCancelable. + if (!mWaitingForResponse) mCancelable = null; - mFactory = null; - } + mFactory = null; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardAdapter.java index bf028aa1..0011a75a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardAdapter.java
@@ -16,6 +16,7 @@ import org.chromium.chrome.browser.modelutil.RecyclerViewAdapter; import org.chromium.chrome.browser.native_page.ContextMenuManager; import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate; +import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.widget.LoadingView; import org.chromium.chrome.browser.widget.RoundedIconGenerator; @@ -41,13 +42,14 @@ private final RoundedIconGenerator mIconGenerator; private final ContextMenuManager mContextMenuManager; private final NativePageNavigationDelegate mNavDelegate; + private final Profile mProfile; private RecyclerView.LayoutManager mLayoutManager; private PropertyModel mCategoryModel; public CategoryCardAdapter(PropertyModel model, RecyclerView.LayoutManager layoutManager, RoundedIconGenerator iconGenerator, ContextMenuManager contextMenuManager, - NativePageNavigationDelegate navDelegate) { + NativePageNavigationDelegate navDelegate, Profile profile) { mCategoryModel = model; mCategoryModel.addObserver(this); mCategoryModel.get(ExploreSitesPage.CATEGORY_LIST_KEY).addObserver(this); @@ -56,6 +58,7 @@ mIconGenerator = iconGenerator; mContextMenuManager = contextMenuManager; mNavDelegate = navDelegate; + mProfile = profile; } @Override @@ -95,7 +98,7 @@ // Position - 1 because there is always title. view.setCategory( mCategoryModel.get(ExploreSitesPage.CATEGORY_LIST_KEY).get(position - 1), - mIconGenerator, mContextMenuManager, mNavDelegate); + mIconGenerator, mContextMenuManager, mNavDelegate, mProfile); } else if (holder.getItemViewType() == ViewType.LOADING) { // Start spinner. LoadingView spinner = holder.itemView.findViewById(R.id.loading);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java index 35a00985..1bb798d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
@@ -4,9 +4,13 @@ package org.chromium.chrome.browser.explore_sites; +import android.content.Context; import android.graphics.Bitmap; +import android.util.DisplayMetrics; +import android.view.WindowManager; import org.chromium.base.Callback; +import org.chromium.base.ContextUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.browser.profiles.Profile; @@ -38,10 +42,7 @@ public static void getCategoryImage( Profile profile, int categoryID, int pixelSize, Callback<Bitmap> callback) { - // TODO(dewittj): Remove this when image decoding works correctly. - Bitmap image = Bitmap.createBitmap(pixelSize, pixelSize, Bitmap.Config.ARGB_8888); - image.eraseColor(android.graphics.Color.GREEN); - callback.onResult(image); + nativeGetCategoryImage(profile, categoryID, pixelSize, callback); } /** @@ -65,6 +66,21 @@ ExploreSitesBackgroundTask.schedule(false /* updateCurrent */); } + /** + * Returns the scale factor on this device. + */ + @CalledByNative + static float getScaleFactorFromDevice() { + // Get DeviceMetrics from context. + DisplayMetrics metrics = new DisplayMetrics(); + ((WindowManager) ContextUtils.getApplicationContext().getSystemService( + Context.WINDOW_SERVICE)) + .getDefaultDisplay() + .getMetrics(metrics); + // Get density and return it. + return metrics.density; + } + static native int nativeGetVariation(); private static native void nativeGetEspCatalog(Profile profile, List<ExploreSitesCategory> result, Callback<List<ExploreSitesCategory>> callback); @@ -74,4 +90,7 @@ private static native void nativeUpdateCatalogFromNetwork( Profile profile, boolean isImmediateFetch, Callback<Boolean> callback); + + private static native void nativeGetCategoryImage( + Profile profile, int categoryID, int pixelSize, Callback<Bitmap> callback); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardView.java index 298ba35..d78b6df 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardView.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.explore_sites; import android.content.Context; +import android.graphics.Bitmap; import android.util.AttributeSet; import android.view.ContextMenu; import android.view.LayoutInflater; @@ -16,13 +17,18 @@ import android.widget.TextView; import org.chromium.chrome.R; +import org.chromium.chrome.browser.modelutil.PropertyKey; +import org.chromium.chrome.browser.modelutil.PropertyModel; +import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor; import org.chromium.chrome.browser.native_page.ContextMenuManager; import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate; +import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.widget.RoundedIconGenerator; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.ui.base.PageTransition; import org.chromium.ui.mojom.WindowOpenDisposition; +import java.util.ArrayList; import java.util.List; /** @@ -30,18 +36,23 @@ */ public class ExploreSitesCategoryCardView extends LinearLayout { private static final int MAX_TILE_COUNT = 8; + private static final int TITLE_LINES = 1; private TextView mTitleView; private GridLayout mTileView; private RoundedIconGenerator mIconGenerator; private ContextMenuManager mContextMenuManager; private NativePageNavigationDelegate mNavigationDelegate; + private Profile mProfile; + private List<PropertyModelChangeProcessor<PropertyModel, ExploreSitesTileView, PropertyKey>> + mModelChangeProcessors; private class CategoryCardInteractionDelegate implements ContextMenuManager.Delegate, OnClickListener, OnCreateContextMenuListener { - private ExploreSitesSite mSite; - public CategoryCardInteractionDelegate(ExploreSitesSite site) { - mSite = site; + private String mSiteUrl; + + public CategoryCardInteractionDelegate(String siteUrl) { + mSiteUrl = siteUrl; } @Override @@ -67,7 +78,7 @@ @Override public String getUrl() { - return mSite.getUrl(); + return mSiteUrl; } @Override @@ -82,8 +93,29 @@ public void onContextMenuCreated(){}; } + private class ExploreSitesSiteViewBinder + implements PropertyModelChangeProcessor + .ViewBinder<PropertyModel, ExploreSitesTileView, PropertyKey> { + @Override + public void bind(PropertyModel model, ExploreSitesTileView view, PropertyKey key) { + if (key == ExploreSitesSite.ICON_KEY) { + view.updateIcon(model.get(ExploreSitesSite.ICON_KEY), + model.get(ExploreSitesSite.TITLE_KEY)); + } else if (key == ExploreSitesSite.TITLE_KEY) { + view.setTitle(model.get(ExploreSitesSite.TITLE_KEY), TITLE_LINES); + } else if (key == ExploreSitesSite.URL_KEY) { + // Attach click handlers. + CategoryCardInteractionDelegate interactionDelegate = + new CategoryCardInteractionDelegate(model.get(ExploreSitesSite.URL_KEY)); + view.setOnClickListener(interactionDelegate); + view.setOnCreateContextMenuListener(interactionDelegate); + } + } + } + public ExploreSitesCategoryCardView(Context context, AttributeSet attrs) { super(context, attrs); + mModelChangeProcessors = new ArrayList<>(MAX_TILE_COUNT); } @Override @@ -94,11 +126,12 @@ } public void setCategory(ExploreSitesCategory category, RoundedIconGenerator iconGenerator, - ContextMenuManager contextMenuManager, - NativePageNavigationDelegate navigationDelegate) { + ContextMenuManager contextMenuManager, NativePageNavigationDelegate navigationDelegate, + Profile profile) { mIconGenerator = iconGenerator; mContextMenuManager = contextMenuManager; mNavigationDelegate = navigationDelegate; + mProfile = profile; updateTitle(category.getTitle()); updateTileViews(category.getSites()); @@ -109,6 +142,13 @@ } public void updateTileViews(List<ExploreSitesSite> sites) { + // Clear observers. + for (PropertyModelChangeProcessor<PropertyModel, ExploreSitesTileView, PropertyKey> + observer : mModelChangeProcessors) { + observer.destroy(); + } + mModelChangeProcessors.clear(); + // Remove extra tiles if too many. if (mTileView.getChildCount() > sites.size()) { mTileView.removeViews(sites.size(), mTileView.getChildCount() - sites.size()); @@ -129,13 +169,17 @@ // Initialize all the non-empty tiles again to update. for (int i = 0; i < tileMax; i++) { ExploreSitesTileView tileView = (ExploreSitesTileView) mTileView.getChildAt(i); - final ExploreSitesSite site = sites.get(i); - tileView.initialize(site, mIconGenerator); + final PropertyModel site = sites.get(i).getModel(); + tileView.initialize(mIconGenerator); - CategoryCardInteractionDelegate interactionDelegate = - new CategoryCardInteractionDelegate(site); - tileView.setOnClickListener(interactionDelegate); - tileView.setOnCreateContextMenuListener(interactionDelegate); + mModelChangeProcessors.add(PropertyModelChangeProcessor.create( + site, tileView, new ExploreSitesSiteViewBinder())); + + // Fetch icon if not present already. + if (site.get(ExploreSitesSite.ICON_KEY) == null) { + ExploreSitesBridge.getSiteImage(mProfile, site.get(ExploreSitesSite.ID_KEY), + (Bitmap icon) -> site.set(ExploreSitesSite.ICON_KEY, icon)); + } } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPage.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPage.java index 1ea3f47..aa0437e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPage.java
@@ -13,6 +13,7 @@ import android.view.ViewGroup; import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.UrlConstants; @@ -105,7 +106,7 @@ host.getActiveTab().getWindowAndroid().addContextMenuCloseListener(mContextMenuManager); CategoryCardAdapter adapterDelegate = new CategoryCardAdapter( - mModel, layoutManager, iconGenerator, mContextMenuManager, navDelegate); + mModel, layoutManager, iconGenerator, mContextMenuManager, navDelegate, profile); RecyclerView recyclerView = (RecyclerView) mView.findViewById(R.id.explore_sites_category_recycler); @@ -116,6 +117,7 @@ recyclerView.setAdapter(adapter); ExploreSitesBridge.getEspCatalog(profile, this::translateToModel); + RecordUserAction.record("Android.ExploreSitesPage.Open"); // TODO(chili): Set layout to be an observer of list model }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java index d5799a5..7a6fb915 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
@@ -11,6 +11,8 @@ import android.view.LayoutInflater; import android.view.View; +import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.explore_sites.ExploreSitesCategory.CategoryType; import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate; @@ -32,6 +34,10 @@ */ public class ExploreSitesSection { private static final int MAX_CATEGORIES = 3; + // This is a number of UMA histogram buckets that should be an upper bound + // of MAX_CATEGORIES over time. If MAX_CATEGORIES changes, this value should + // be updated only upwards. + private static final int MAX_CATEGORIES_HISTOGRAM_BUCKETS = 3; @TileStyle private int mStyle; @@ -51,6 +57,7 @@ } private void initialize() { + RecordUserAction.record("Android.ExploreSitesNTP.Opened"); ExploreSitesBridge.getEspCatalog(mProfile, this::gotEspCatalog); } @@ -98,7 +105,7 @@ return category; } - private void createTileView(ExploreSitesCategory category) { + private void createTileView(int tileIndex, ExploreSitesCategory category) { ExploreSitesCategoryTileView tileView; if (mStyle == TileStyle.MODERN_CONDENSED) { tileView = (ExploreSitesCategoryTileView) LayoutInflater.from(getContext()) @@ -111,7 +118,7 @@ } tileView.initialize(category); mExploreSection.addView(tileView); - tileView.setOnClickListener((View v) -> onClicked(category, v)); + tileView.setOnClickListener((View v) -> onClicked(tileIndex, category, v)); } /** @@ -120,10 +127,14 @@ * from the ExploreSitesBridge. */ private void gotEspCatalog(List<ExploreSitesCategory> categoryList) { + boolean loadingCatalogFromNetwork = false; if (categoryList == null || categoryList.size() == 0) { + loadingCatalogFromNetwork = true; ExploreSitesBridge.updateCatalogFromNetwork(mProfile, true /*isImmediateFetch*/, (Boolean success) -> { updateCategoryIcons(); }); } + RecordHistogram.recordBooleanHistogram( + "ExploreSites.NTPLoadingCatalogFromNetwork", loadingCatalogFromNetwork); // Initialize with defaults right away. initializeCategoryTiles(categoryList); } @@ -167,17 +178,19 @@ int tileCount = 0; for (final ExploreSitesCategory category : categoryList) { + if (tileCount >= MAX_CATEGORIES) break; + createTileView(tileCount, category); tileCount++; - if (tileCount > MAX_CATEGORIES) break; - createTileView(category); } - createTileView(createMoreTileCategory()); + createTileView(tileCount, createMoreTileCategory()); if (needIcons) { updateCategoryIcons(); } } - private void onClicked(ExploreSitesCategory category, View v) { + private void onClicked(int tileIndex, ExploreSitesCategory category, View v) { + RecordHistogram.recordLinearCountHistogram("ExploreSites.ClickedNTPCategoryIndex", + tileIndex, 0, MAX_CATEGORIES_HISTOGRAM_BUCKETS, MAX_CATEGORIES_HISTOGRAM_BUCKETS); mNavigationDelegate.openUrl(WindowOpenDisposition.CURRENT_TAB, new LoadUrlParams(category.getUrl(), PageTransition.AUTO_BOOKMARK)); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSite.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSite.java index 8be10ab..cf59acf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSite.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSite.java
@@ -7,40 +7,33 @@ import android.graphics.Bitmap; import org.chromium.base.annotations.CalledByNative; +import org.chromium.chrome.browser.modelutil.PropertyModel; /** * An object encapsulating info for a website. */ public class ExploreSitesSite { - private int mSiteId; - private String mSiteTitle; - private Bitmap mIcon; - private String mUrl; + static final PropertyModel.ReadableIntPropertyKey ID_KEY = + new PropertyModel.ReadableIntPropertyKey(); + static final PropertyModel.ReadableObjectPropertyKey<String> TITLE_KEY = + new PropertyModel.ReadableObjectPropertyKey<>(); + static final PropertyModel.ReadableObjectPropertyKey<String> URL_KEY = + new PropertyModel.ReadableObjectPropertyKey<>(); + static final PropertyModel.WritableObjectPropertyKey<Bitmap> ICON_KEY = + new PropertyModel.WritableObjectPropertyKey<>(); + + private PropertyModel mModel; public ExploreSitesSite(int id, String title, String url) { - mSiteId = id; - mSiteTitle = title; - mUrl = url; + mModel = new PropertyModel.Builder(ID_KEY, TITLE_KEY, URL_KEY, ICON_KEY) + .with(ID_KEY, id) + .with(TITLE_KEY, title) + .with(URL_KEY, url) + .build(); } - public int getId() { - return mSiteId; - } - - public void setIcon(Bitmap icon) { - mIcon = icon; - } - - public String getTitle() { - return mSiteTitle; - } - - public String getUrl() { - return mUrl; - } - - public Bitmap getIcon() { - return mIcon; + public PropertyModel getModel() { + return mModel; } @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java index 20c097e7..36ea1ca9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java
@@ -19,8 +19,6 @@ * View for a category name and site tiles. */ public class ExploreSitesTileView extends TileWithTextView { - private static final int TITLE_LINES = 1; - private final int mIconSizePx; private RoundedIconGenerator mIconGenerator; @@ -29,10 +27,8 @@ mIconSizePx = getResources().getDimensionPixelSize(R.dimen.tile_view_icon_size); } - public void initialize(ExploreSitesSite site, RoundedIconGenerator generator) { + public void initialize(RoundedIconGenerator generator) { mIconGenerator = generator; - super.initialize(site.getTitle(), /* showOfflineBadge = */ false, - getDrawableForBitmap(site.getIcon(), site.getTitle()), TITLE_LINES); } public void updateIcon(Bitmap iconImage, String text) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modelutil/RecyclerViewAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/RecyclerViewAdapter.java index 7d6949e..7fa7ce9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/modelutil/RecyclerViewAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/RecyclerViewAdapter.java
@@ -63,6 +63,16 @@ void onBindViewHolder(VH viewHolder, int position, @Nullable P payload); /** + * Called when the {@link View} owned by {@code viewHolder} no longer needs to be attached + * to its parent {@link RecyclerView}. This is a good place to free up expensive resources + * that might be owned by the particular {@link View} or {@code viewHolder}. + * @param viewHolder A view holder that will be recycled. + * @see RecyclerView.Adapter#onViewRecycled(ViewHolder) + */ + default void + onViewRecycled(VH viewHolder) {} + + /** * @param position The position of an item to be dismissed. * @return The set of item positions that should be dismissed simultaneously when dismissing * the item at the given {@code position} (including the position itself), or an @@ -163,6 +173,11 @@ } @Override + public void onViewRecycled(VH holder) { + mDelegate.onViewRecycled(holder); + } + + @Override public void onItemRangeInserted(ListObservable source, int index, int count) { notifyItemRangeInserted(index, count); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteCoordinator.java index 11f1d94..88265ce4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteCoordinator.java
@@ -25,6 +25,7 @@ import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxResultItem; import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxSuggestionDelegate; import org.chromium.chrome.browser.omnibox.OmniboxSuggestionsList.OmniboxSuggestionListEmbedder; +import org.chromium.chrome.browser.omnibox.UrlBar.UrlTextChangeListener; import org.chromium.chrome.browser.omnibox.VoiceSuggestionProvider.VoiceResult; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.toolbar.ToolbarDataProvider; @@ -40,7 +41,8 @@ /** * Coordinator that handles the interactions with the autocomplete system. */ -public class AutocompleteCoordinator implements OnSuggestionsReceivedListener { +public class AutocompleteCoordinator + implements OnSuggestionsReceivedListener, UrlTextChangeListener { private static final String TAG = "cr_Autocomplete"; // Delay triggering the omnibox results upon key press to allow the location bar to repaint @@ -93,6 +95,11 @@ */ interface AutocompleteDelegate { /** + * Notified that the URL text has changed. + */ + void onUrlTextChanged(); + + /** * Notified that suggestions have changed. * @param autocompleteText The inline autocomplete text that can be appended to the * currently entered user text. @@ -397,7 +404,7 @@ if (mSuggestionsShown == visible) return; mSuggestionsShown = visible; if (mSuggestionList != null) { - final boolean isShowing = mSuggestionList.isShown(); + final boolean isShowing = mSuggestionList.getVisibility() == View.VISIBLE; if (visible && !isShowing) { mIgnoreOmniboxItemSelection = true; // Reset to default value. @@ -613,7 +620,11 @@ * Notifies the autocomplete system that the text has changed that drives autocomplete and the * autocomplete suggestions should be updated. */ + @Override public void onTextChangedForAutocomplete() { + // crbug.com/764749 + Log.w(TAG, "onTextChangedForAutocomplete"); + if (mShouldPreventOmniboxAutocomplete) return; cancelPendingAutocompleteStart(); @@ -667,6 +678,8 @@ mDeferredNativeRunnables.add(mRequestSuggestions); } } + + mDelegate.onUrlTextChanged(); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java index 4a377a3..d3436ec 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -39,7 +39,6 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.CommandLine; -import org.chromium.base.Log; import org.chromium.base.ObserverList; import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordUserAction; @@ -107,7 +106,7 @@ protected BottomSheet mBottomSheet; protected UrlBarCoordinator mUrlCoordinator; - private AutocompleteCoordinator mAutocompleteCoordinator; + protected AutocompleteCoordinator mAutocompleteCoordinator; protected ToolbarDataProvider mToolbarDataProvider; private ObserverList<UrlFocusChangeListener> mUrlFocusChangeListeners = new ObserverList<>(); @@ -269,6 +268,7 @@ }; mAutocompleteCoordinator = new AutocompleteCoordinator(this, this, embedder, mUrlCoordinator); + mUrlCoordinator.setUrlTextChangeListener(mAutocompleteCoordinator); mMicButton = (AppCompatImageButton) findViewById(R.id.mic_button); @@ -640,13 +640,9 @@ } @Override - public void onTextChangedForAutocomplete() { - // crbug.com/764749 - Log.w(TAG, "onTextChangedForAutocomplete"); - + public void onUrlTextChanged() { updateButtonVisibility(); updateNavigationButton(); - mAutocompleteCoordinator.onTextChangedForAutocomplete(); } @Override @@ -669,7 +665,7 @@ // This must be happen after requestUrlFocus(), which changes the selection. mUrlCoordinator.setUrlBarData(UrlBarData.forNonUrlText(pastedText), UrlBar.ScrollType.NO_SCROLL, UrlBarCoordinator.SelectionState.SELECT_END); - onTextChangedForAutocomplete(); + mAutocompleteCoordinator.onTextChangedForAutocomplete(); } else { ToolbarManager.recordOmniboxFocusReason(ToolbarManager.OmniboxFocusReason.FAKE_BOX_TAP); } @@ -1384,7 +1380,7 @@ mToolbarDataProvider.getUrlBarData().getEditingOrDisplayText())) { mAutocompleteCoordinator.startZeroSuggest(); } else { - onTextChangedForAutocomplete(); + mAutocompleteCoordinator.onTextChangedForAutocomplete(); } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsList.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsList.java index 422e878..b942dcd87 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestionsList.java
@@ -9,6 +9,7 @@ import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.support.annotation.Nullable; import android.support.v4.view.ViewCompat; import android.text.TextUtils; @@ -220,7 +221,15 @@ /** * Update the layout params to ensure the suggestion popup is properly sized. */ + // TODO(tedchoc): This should likely be done in measure/layout instead of just manipulating + // the layout params. Investigate converting to that flow. void updateLayoutParams() { + // If in the middle of a layout pass, post till it is completed to avoid the layout param + // update being ignored. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && isInLayout()) { + post(this::updateLayoutParams); + return; + } boolean updateLayout = false; FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams(); if (layoutParams == null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java index e820f90..fc62d72e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -69,6 +69,7 @@ private int mUrlDirection; private UrlBarDelegate mUrlBarDelegate; + private UrlTextChangeListener mTextChangeListener; private UrlBarTextContextMenuDelegate mTextContextMenuDelegate; private UrlDirectionListener mUrlDirectionListener; @@ -156,12 +157,6 @@ boolean allowKeyboardLearning(); /** - * Called when the text state has changed and the autocomplete suggestions should be - * refreshed. - */ - void onTextChangedForAutocomplete(); - - /** * Called to notify that back key has been pressed while the URL bar has focus. */ void backKeyPressed(); @@ -178,6 +173,15 @@ boolean shouldCutCopyVerbatim(); } + /** Provides updates about the URL text changes. */ + public interface UrlTextChangeListener { + /** + * Called when the text state has changed and the autocomplete suggestions should be + * refreshed. + */ + void onTextChangedForAutocomplete(); + } + /** Delegate that provides the additional functionality to the textual context menus. */ interface UrlBarTextContextMenuDelegate { /** @return The text to be pasted into the UrlBar. */ @@ -525,6 +529,14 @@ mUrlBarDelegate = delegate; } + /** + * Set the listener to be notified when the URL text has changed. + * @param listener The listener to be notified. + */ + public void setUrlTextChangeListener(UrlTextChangeListener listener) { + mTextChangeListener = listener; + } + @Override public boolean onTextContextMenuItem(int id) { if (mTextContextMenuDelegate == null) return super.onTextContextMenuItem(id); @@ -845,12 +857,12 @@ if (DEBUG) { Log.i(TAG, "onAutocompleteTextStateChanged: DIS[%b]", updateDisplay); } - if (mUrlBarDelegate == null) return; + if (mTextChangeListener == null) return; if (updateDisplay) limitDisplayableLength(); // crbug.com/764749 Log.w(TAG, "Text change observed, triggering autocomplete."); - mUrlBarDelegate.onTextChangedForAutocomplete(); + mTextChangeListener.onTextChangedForAutocomplete(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java index 96ff63dd..53e42b60 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java
@@ -14,6 +14,7 @@ import org.chromium.chrome.browser.omnibox.UrlBar.ScrollType; import org.chromium.chrome.browser.omnibox.UrlBar.UrlBarDelegate; import org.chromium.chrome.browser.omnibox.UrlBar.UrlDirectionListener; +import org.chromium.chrome.browser.omnibox.UrlBar.UrlTextChangeListener; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -53,6 +54,11 @@ mMediator.setDelegate(delegate); } + /** @see UrlBarMediator#setDelegate(UrlBarDelegate) */ + public void setUrlTextChangeListener(UrlTextChangeListener listener) { + mMediator.setUrlTextChangeListener(listener); + } + /** @see UrlBarMediator#setUrlBarData(UrlBarData, int, int) */ public boolean setUrlBarData( UrlBarData data, @ScrollType int scrollType, @SelectionState int state) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java index d41b30c7..1087c17 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
@@ -21,6 +21,7 @@ import org.chromium.chrome.browser.omnibox.UrlBar.ScrollType; import org.chromium.chrome.browser.omnibox.UrlBar.UrlBarDelegate; import org.chromium.chrome.browser.omnibox.UrlBar.UrlDirectionListener; +import org.chromium.chrome.browser.omnibox.UrlBar.UrlTextChangeListener; import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState; import org.chromium.chrome.browser.omnibox.UrlBarProperties.AutocompleteText; import org.chromium.chrome.browser.omnibox.UrlBarProperties.UrlBarTextState; @@ -57,6 +58,11 @@ mModel.set(UrlBarProperties.DELEGATE, delegate); } + /** Set the listener to be notified when the url text chagnes. */ + public void setUrlTextChangeListener(UrlTextChangeListener listener) { + mModel.set(UrlBarProperties.URL_TEXT_CHANGE_LISTENER, listener); + } + /** * Updates the text content of the UrlBar. *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarProperties.java index 5738c02..ca2a3db 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarProperties.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarProperties.java
@@ -15,6 +15,7 @@ import org.chromium.chrome.browser.omnibox.UrlBar.UrlBarDelegate; import org.chromium.chrome.browser.omnibox.UrlBar.UrlBarTextContextMenuDelegate; import org.chromium.chrome.browser.omnibox.UrlBar.UrlDirectionListener; +import org.chromium.chrome.browser.omnibox.UrlBar.UrlTextChangeListener; import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState; import java.util.Locale; @@ -110,6 +111,10 @@ public static final WritableObjectPropertyKey<UrlDirectionListener> URL_DIRECTION_LISTENER = new WritableObjectPropertyKey<>(); + /** The callback to be notified on text changes. */ + public static final WritableObjectPropertyKey<UrlTextChangeListener> URL_TEXT_CHANGE_LISTENER = + new WritableObjectPropertyKey<>(); + /** Specifies whether dark text colors should be used in the view. */ public static final WritableBooleanPropertyKey USE_DARK_TEXT_COLORS = new WritableBooleanPropertyKey(); @@ -118,8 +123,8 @@ public static final WritableObjectPropertyKey<WindowDelegate> WINDOW_DELEGATE = new WritableObjectPropertyKey<>(); - public static final PropertyKey[] ALL_KEYS = - new PropertyKey[] {ACTION_MODE_CALLBACK, ALLOW_FOCUS, AUTOCOMPLETE_TEXT, DELEGATE, - FOCUS_CHANGE_CALLBACK, SHOW_CURSOR, TEXT_CONTEXT_MENU_DELEGATE, TEXT_STATE, - URL_DIRECTION_LISTENER, USE_DARK_TEXT_COLORS, WINDOW_DELEGATE}; + public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {ACTION_MODE_CALLBACK, + ALLOW_FOCUS, AUTOCOMPLETE_TEXT, DELEGATE, FOCUS_CHANGE_CALLBACK, SHOW_CURSOR, + TEXT_CONTEXT_MENU_DELEGATE, TEXT_STATE, URL_DIRECTION_LISTENER, + URL_TEXT_CHANGE_LISTENER, USE_DARK_TEXT_COLORS, WINDOW_DELEGATE}; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java index d0300e3a..9a1f8df 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java
@@ -69,6 +69,8 @@ updateTextColors(view, model.get(UrlBarProperties.USE_DARK_TEXT_COLORS)); } else if (UrlBarProperties.URL_DIRECTION_LISTENER.equals(propertyKey)) { view.setUrlDirectionListener(model.get(UrlBarProperties.URL_DIRECTION_LISTENER)); + } else if (UrlBarProperties.URL_TEXT_CHANGE_LISTENER.equals(propertyKey)) { + view.setUrlTextChangeListener(model.get(UrlBarProperties.URL_TEXT_CHANGE_LISTENER)); } else if (UrlBarProperties.WINDOW_DELEGATE.equals(propertyKey)) { view.setWindowDelegate(model.get(UrlBarProperties.WINDOW_DELEGATE)); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java index 815cdf9..3b90470e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePermissionsFetcher.java
@@ -234,6 +234,17 @@ } private void setException(int contentSettingsType) { + @ContentSettingException.Type + int exceptionType; + for (exceptionType = 0; exceptionType < ContentSettingException.Type.NUM_ENTRIES; + exceptionType++) { + if (contentSettingsType == ContentSettingException.CONTENT_TYPES[exceptionType]) break; + } + assert contentSettingsType + == ContentSettingException.CONTENT_TYPES[exceptionType] + : "Unexpected content setting type received: " + + contentSettingsType; + for (ContentSettingException exception : WebsitePreferenceBridge.getContentSettingsExceptions(contentSettingsType)) { // The pattern "*" represents the default setting, not a specific website. @@ -241,13 +252,7 @@ WebsiteAddress address = WebsiteAddress.create(exception.getPattern()); if (address == null) continue; Website site = findOrCreateSite(address, null); - for (int i = 0; i < ContentSettingException.CONTENT_TYPES.length; i++) { - if (contentSettingsType == ContentSettingException.CONTENT_TYPES[i]) { - site.setContentSettingException(i, exception); - return; - } - } - assert false : "Unexpected content setting type received: " + contentSettingsType; + site.setContentSettingException(exceptionType, exception); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java index b27ac35..2e62d56 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
@@ -90,7 +90,7 @@ getAutocompleteCoordinator().setShouldPreventOmniboxAutocomplete( mPendingSearchPromoDecision); if (!TextUtils.isEmpty(mUrlCoordinator.getTextWithAutocomplete())) { - onTextChangedForAutocomplete(); + mAutocompleteCoordinator.onTextChangedForAutocomplete(); } if (mPendingBeginQuery) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java index f73b4eb..b0ec39d4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -749,9 +749,6 @@ // Toolbar and LocationBar calls that are not relevant here. @Override - public void onTextChangedForAutocomplete() {} - - @Override public void backKeyPressed() { assert false : "The URL bar should never take focus in CCTs."; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java index 83d50f5..ab99f13 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java
@@ -48,12 +48,17 @@ * @param titleLines The number of text lines to use for the tile title. */ public void initialize(String title, boolean showOfflineBadge, Drawable icon, int titleLines) { - mTitleView.setLines(titleLines); - mTitleView.setText(title); + setTitle(title, titleLines); setOfflineBadgeVisibility(showOfflineBadge); setIconDrawable(icon); } + /** Sets the title text and number lines. */ + public void setTitle(String title, int titleLines) { + mTitleView.setLines(titleLines); + mTitleView.setText(title); + } + /** * Renders the icon or clears it from the view if the icon is null. */
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 8359743..1c0457a 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -517,7 +517,6 @@ "java/src/org/chromium/chrome/browser/download/home/list/ListItem.java", "java/src/org/chromium/chrome/browser/download/home/list/ListItemModel.java", "java/src/org/chromium/chrome/browser/download/home/list/holder/CustomViewHolder.java", - "java/src/org/chromium/chrome/browser/download/home/list/holder/DateViewHolder.java", "java/src/org/chromium/chrome/browser/download/home/list/holder/GenericViewHolder.java", "java/src/org/chromium/chrome/browser/download/home/list/holder/ImageViewHolder.java", "java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressImageViewHolder.java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java index 1da03d1..b98a78b 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java
@@ -22,7 +22,6 @@ import org.chromium.base.CollectionUtil; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.download.home.filter.OfflineItemFilterSource; -import org.chromium.chrome.browser.download.home.list.ListItem.DateListItem; import org.chromium.chrome.browser.download.home.list.ListItem.OfflineItemListItem; import org.chromium.chrome.browser.download.home.list.ListItem.SectionHeaderListItem; import org.chromium.chrome.browser.download.home.list.ListItem.SeparatorViewListItem; @@ -32,6 +31,7 @@ import java.util.Calendar; import java.util.Collections; +import java.util.Date; /** Unit tests for the DateOrderedListMutator class. */ @RunWith(BaseRobolectricTestRunner.class) @@ -84,11 +84,10 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1)); DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); - Assert.assertEquals(3, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0)); + Assert.assertEquals(2, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 1), item1); + mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 1), item1); } /** @@ -107,12 +106,11 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); - Assert.assertEquals(4, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0)); + Assert.assertEquals(3, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 2), item1); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 1), item2); + mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 2), item1); + assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 1), item2); } /** @@ -133,15 +131,76 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); - Assert.assertEquals(6, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0)); + Assert.assertEquals(5, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 2), item1); - assertSeparator(mModel.get(3), buildCalendar(2018, 1, 1, 0), false); + mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 2), item1); + assertSeparator(mModel.get(2), buildCalendar(2018, 1, 1, 0), false); assertSectionHeader( - mModel.get(4), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_AUDIO); - assertOfflineItem(mModel.get(5), buildCalendar(2018, 1, 1, 1), item2); + mModel.get(3), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_AUDIO, false); + assertOfflineItem(mModel.get(4), buildCalendar(2018, 1, 1, 1), item2); + } + + /** + * Action List + * 1. Set(item1 @ 2:00 1/1/2018 Video, [ DATE @ 0:00 1/1/2018, + * item2 @ 1:00 1/1/2018 Image) SECTION @ Video, + * item1 @ 2:00 1/1/2018, + * ----------------------- + * SECTION @ Image, + * item2 @ 1:00 1/1/2018 ] + */ + @Test + public void testShowMenuButtonForImageSectionWithoutDate() { + OfflineItem item1 = + buildItem("1", buildCalendar(2018, 1, 1, 2), OfflineItemFilter.FILTER_VIDEO); + OfflineItem item2 = + buildItem("2", buildCalendar(2018, 1, 1, 1), OfflineItemFilter.FILTER_IMAGE); + when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); + DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); + + Assert.assertEquals(5, mModel.size()); + assertSectionHeader( + mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + Assert.assertFalse(((SectionHeaderListItem) mModel.get(0)).showMenu); + + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 2), item1); + assertSeparator(mModel.get(2), buildCalendar(2018, 1, 1, 0), false); + assertSectionHeader( + mModel.get(3), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_IMAGE, false); + Assert.assertTrue(((SectionHeaderListItem) mModel.get(3)).showMenu); + assertOfflineItem(mModel.get(4), buildCalendar(2018, 1, 1, 1), item2); + } + + /** + * Action List + * 1. Set(item1 @ 2:00 1/1/2018 Image, [ DATE @ 0:00 1/1/2018, + * item2 @ 1:00 1/1/2018 Page) SECTION @ Image, + * item1 @ 2:00 1/1/2018, + * ----------------------- + * SECTION @ Page, + * item2 @ 1:00 1/1/2018 ] + */ + @Test + public void testShowMenuButtonForImageSectionWithDate() { + OfflineItem item1 = + buildItem("1", buildCalendar(2018, 1, 1, 2), OfflineItemFilter.FILTER_IMAGE); + OfflineItem item2 = + buildItem("2", buildCalendar(2018, 1, 1, 1), OfflineItemFilter.FILTER_PAGE); + when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); + DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); + + Assert.assertEquals(5, mModel.size()); + assertSectionHeader( + mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_IMAGE, true); + Assert.assertTrue(((SectionHeaderListItem) mModel.get(0)).showMenu); + + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 2), item1); + assertSeparator(mModel.get(2), buildCalendar(2018, 1, 1, 0), false); + assertSectionHeader( + mModel.get(3), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_PAGE, false); + Assert.assertFalse(((SectionHeaderListItem) mModel.get(3)).showMenu); + assertOfflineItem(mModel.get(4), buildCalendar(2018, 1, 1, 1), item2); } /** @@ -163,16 +222,14 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); - Assert.assertEquals(7, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); + Assert.assertEquals(5, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 0), item1); - assertSeparator(mModel.get(3), buildCalendar(2018, 1, 2, 0), true); - assertDateHeader(mModel.get(4), buildCalendar(2018, 1, 1, 0)); + mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 0), item1); + assertSeparator(mModel.get(2), buildCalendar(2018, 1, 2, 0), true); assertSectionHeader( - mModel.get(5), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_AUDIO); - assertOfflineItem(mModel.get(6), buildCalendar(2018, 1, 1, 0), item2); + mModel.get(3), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_AUDIO, true); + assertOfflineItem(mModel.get(4), buildCalendar(2018, 1, 1, 0), item2); } /** @@ -191,12 +248,11 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); - Assert.assertEquals(4, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0)); + Assert.assertEquals(3, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 5), item2); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 4), item1); + mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 5), item2); + assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 4), item1); } /** @@ -218,16 +274,14 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); - Assert.assertEquals(7, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); + Assert.assertEquals(5, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 4), item1); - assertSeparator(mModel.get(3), buildCalendar(2018, 1, 2, 0), true); - assertDateHeader(mModel.get(4), buildCalendar(2018, 1, 1, 0)); + mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 4), item1); + assertSeparator(mModel.get(2), buildCalendar(2018, 1, 2, 0), true); assertSectionHeader( - mModel.get(5), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(6), buildCalendar(2018, 1, 1, 5), item2); + mModel.get(3), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(4), buildCalendar(2018, 1, 1, 5), item2); } /** @@ -249,16 +303,14 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); - Assert.assertEquals(7, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); + Assert.assertEquals(5, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 4), item1); - assertSeparator(mModel.get(3), buildCalendar(2018, 1, 2, 0), true); - assertDateHeader(mModel.get(4), buildCalendar(2018, 1, 1, 0)); + mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 4), item1); + assertSeparator(mModel.get(2), buildCalendar(2018, 1, 2, 0), true); assertSectionHeader( - mModel.get(5), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_PAGE); - assertOfflineItem(mModel.get(6), buildCalendar(2018, 1, 1, 5), item2); + mModel.get(3), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_PAGE, true); + assertOfflineItem(mModel.get(4), buildCalendar(2018, 1, 1, 5), item2); } /** @@ -278,16 +330,14 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); - Assert.assertEquals(7, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); + Assert.assertEquals(5, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 3), item2); - assertSeparator(mModel.get(3), buildCalendar(2018, 1, 2, 0), true); - assertDateHeader(mModel.get(4), buildCalendar(2018, 1, 1, 0)); + mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 3), item2); + assertSeparator(mModel.get(2), buildCalendar(2018, 1, 2, 0), true); assertSectionHeader( - mModel.get(5), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(6), buildCalendar(2018, 1, 1, 4), item1); + mModel.get(3), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(4), buildCalendar(2018, 1, 1, 4), item1); } /** @@ -308,9 +358,8 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1)); list.onItemsAdded(CollectionUtil.newArrayList(item1)); - Assert.assertEquals(3, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0)); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 4), item1); + Assert.assertEquals(2, mModel.size()); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 4), item1); } /** @@ -345,10 +394,9 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); list.onItemsAdded(CollectionUtil.newArrayList(item2)); - Assert.assertEquals(4, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 2), item2); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 2, 1), item1); + Assert.assertEquals(3, mModel.size()); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 2), item2); + assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 1), item1); // Add an item on an earlier day that will be placed first. OfflineItem item3 = @@ -356,13 +404,11 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2, item3)); list.onItemsAdded(CollectionUtil.newArrayList(item3)); - Assert.assertEquals(8, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 3, 0)); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 3, 2), item3); - assertSeparator(mModel.get(3), buildCalendar(2018, 1, 3, 0), true); - assertDateHeader(mModel.get(4), buildCalendar(2018, 1, 2, 0)); - assertOfflineItem(mModel.get(6), buildCalendar(2018, 1, 2, 2), item2); - assertOfflineItem(mModel.get(7), buildCalendar(2018, 1, 2, 1), item1); + Assert.assertEquals(6, mModel.size()); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 3, 2), item3); + assertSeparator(mModel.get(2), buildCalendar(2018, 1, 3, 0), true); + assertOfflineItem(mModel.get(4), buildCalendar(2018, 1, 2, 2), item2); + assertOfflineItem(mModel.get(5), buildCalendar(2018, 1, 2, 1), item1); } /** @@ -399,10 +445,9 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); list.onItemsAdded(CollectionUtil.newArrayList(item2)); - Assert.assertEquals(4, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 4), item1); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 2, 3), item2); + Assert.assertEquals(3, mModel.size()); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 4), item1); + assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 3), item2); // Add an item on a later day that will be placed last. OfflineItem item3 = @@ -410,13 +455,11 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2, item3)); list.onItemsAdded(CollectionUtil.newArrayList(item3)); - Assert.assertEquals(8, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 4), item1); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 2, 3), item2); - assertSeparator(mModel.get(4), buildCalendar(2018, 1, 2, 0), true); - assertDateHeader(mModel.get(5), buildCalendar(2018, 1, 1, 0)); - assertOfflineItem(mModel.get(7), buildCalendar(2018, 1, 1, 4), item3); + Assert.assertEquals(6, mModel.size()); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 4), item1); + assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 3), item2); + assertSeparator(mModel.get(3), buildCalendar(2018, 1, 2, 0), true); + assertOfflineItem(mModel.get(5), buildCalendar(2018, 1, 1, 4), item3); } /** @@ -465,11 +508,10 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item2)); list.onItemsRemoved(CollectionUtil.newArrayList(item1)); - Assert.assertEquals(3, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); + Assert.assertEquals(2, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 2), item2); + mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 2), item2); } /** @@ -496,11 +538,10 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1)); list.onItemsRemoved(CollectionUtil.newArrayList(item2)); - Assert.assertEquals(3, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); + Assert.assertEquals(2, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 3), item1); + mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 3), item1); } /** @@ -525,16 +566,15 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1, item2)); DateOrderedListMutator list = new DateOrderedListMutator(mSource, mModel); mModel.addObserver(mObserver); - Assert.assertEquals(6, mModel.size()); + Assert.assertEquals(5, mModel.size()); when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item2)); list.onItemsRemoved(CollectionUtil.newArrayList(item1)); - Assert.assertEquals(3, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); + Assert.assertEquals(2, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_IMAGE); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 2), item2); + mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_IMAGE, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 2), item2); } /** @@ -564,11 +604,10 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1)); list.onItemsRemoved(CollectionUtil.newArrayList(item2)); - Assert.assertEquals(3, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 3, 0)); + Assert.assertEquals(2, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 3, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 3, 3), item1); + mModel.get(0), buildCalendar(2018, 1, 3, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 3, 3), item1); } /** @@ -604,18 +643,16 @@ .thenReturn(CollectionUtil.newArrayList(item1, item2, item3, item4)); list.onItemsAdded(CollectionUtil.newArrayList(item1, item2, item3, item4)); - Assert.assertEquals(9, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); + Assert.assertEquals(7, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 12), item4); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 2, 10), item3); - assertSeparator(mModel.get(4), buildCalendar(2018, 1, 2, 0), true); - assertDateHeader(mModel.get(5), buildCalendar(2018, 1, 1, 0)); + mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 12), item4); + assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 10), item3); + assertSeparator(mModel.get(3), buildCalendar(2018, 1, 2, 0), true); assertSectionHeader( - mModel.get(6), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(7), buildCalendar(2018, 1, 1, 6), item1); - assertOfflineItem(mModel.get(8), buildCalendar(2018, 1, 1, 4), item2); + mModel.get(4), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(5), buildCalendar(2018, 1, 1, 6), item1); + assertOfflineItem(mModel.get(6), buildCalendar(2018, 1, 1, 4), item2); } /** @@ -653,11 +690,10 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(item1)); list.onItemsRemoved(CollectionUtil.newArrayList(item2, item3, item4)); - Assert.assertEquals(3, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0)); + Assert.assertEquals(2, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 6), item1); + mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 6), item1); } /** @@ -686,11 +722,10 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(newItem1)); list.onItemUpdated(item1, newItem1); - Assert.assertEquals(3, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0)); + Assert.assertEquals(2, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 4), newItem1); + mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 4), newItem1); } /** @@ -722,12 +757,11 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(newItem1, item2)); list.onItemUpdated(item1, newItem1); - Assert.assertEquals(4, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0)); + Assert.assertEquals(3, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 4), item2); - assertOfflineItem(mModel.get(3), buildCalendar(2018, 1, 1, 3), newItem1); + mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 4), item2); + assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 3), newItem1); } /** @@ -761,14 +795,13 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(newItem1, item2)); list.onItemUpdated(item1, newItem1); - Assert.assertEquals(6, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 1, 0)); + Assert.assertEquals(5, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 1, 4), item2); + mModel.get(0), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 1, 4), item2); assertSectionHeader( - mModel.get(4), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_IMAGE); - assertOfflineItem(mModel.get(5), buildCalendar(2018, 1, 1, 3), newItem1); + mModel.get(3), buildCalendar(2018, 1, 1, 0), OfflineItemFilter.FILTER_IMAGE, false); + assertOfflineItem(mModel.get(4), buildCalendar(2018, 1, 1, 3), newItem1); } /** @@ -797,11 +830,10 @@ when(mSource.getItems()).thenReturn(CollectionUtil.newArrayList(newItem1)); list.onItemUpdated(item1, newItem1); - Assert.assertEquals(3, mModel.size()); - assertDateHeader(mModel.get(0), buildCalendar(2018, 1, 2, 0)); + Assert.assertEquals(2, mModel.size()); assertSectionHeader( - mModel.get(1), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO); - assertOfflineItem(mModel.get(2), buildCalendar(2018, 1, 2, 6), newItem1); + mModel.get(0), buildCalendar(2018, 1, 2, 0), OfflineItemFilter.FILTER_VIDEO, true); + assertOfflineItem(mModel.get(1), buildCalendar(2018, 1, 2, 6), newItem1); } private static Calendar buildCalendar(int year, int month, int dayOfMonth, int hourOfDay) { @@ -820,44 +852,35 @@ return item; } - private static void assertDatesAreEqual(ListItem item, Calendar calendar) { - Assert.assertTrue(item instanceof DateListItem); + private static void assertDatesAreEqual(Date date, Calendar calendar) { Calendar calendar2 = CalendarFactory.get(); - calendar2.setTime(((DateListItem) item).date); + calendar2.setTime(date); Assert.assertEquals(calendar.getTimeInMillis(), calendar2.getTimeInMillis()); } - private static void assertDateHeader(ListItem item, Calendar calendar) { - Assert.assertTrue(item instanceof DateListItem); - Assert.assertFalse(item instanceof OfflineItemListItem); - Assert.assertFalse(item instanceof SectionHeaderListItem); - Assert.assertFalse(item instanceof SeparatorViewListItem); - - assertDatesAreEqual(item, calendar); - Assert.assertEquals(DateListItem.generateStableIdForDayOfYear(calendar), item.stableId); - } - private static void assertOfflineItem( ListItem item, Calendar calendar, OfflineItem offlineItem) { - assertDatesAreEqual(item, calendar); Assert.assertTrue(item instanceof OfflineItemListItem); + assertDatesAreEqual(((OfflineItemListItem) item).date, calendar); Assert.assertEquals(OfflineItemListItem.generateStableId(offlineItem), item.stableId); Assert.assertEquals(offlineItem, ((OfflineItemListItem) item).item); } private static void assertSectionHeader( - ListItem item, Calendar calendar, @OfflineItemFilter int filter) { - assertDatesAreEqual(item, calendar); + ListItem item, Calendar calendar, @OfflineItemFilter int filter, boolean showDate) { Assert.assertTrue(item instanceof SectionHeaderListItem); - Assert.assertEquals(filter, ((SectionHeaderListItem) item).filter); + SectionHeaderListItem sectionHeader = (SectionHeaderListItem) item; + assertDatesAreEqual(sectionHeader.date, calendar); + Assert.assertEquals(filter, sectionHeader.filter); Assert.assertEquals( SectionHeaderListItem.generateStableId(calendar.getTimeInMillis(), filter), item.stableId); + Assert.assertEquals(sectionHeader.showDate, showDate); } private static void assertSeparator(ListItem item, Calendar calendar, boolean isDateDivider) { - assertDatesAreEqual(item, calendar); Assert.assertTrue(item instanceof SeparatorViewListItem); + assertDatesAreEqual(((SeparatorViewListItem) item).date, calendar); Assert.assertEquals(isDateDivider, ((SeparatorViewListItem) item).isDateDivider()); } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryUnitTest.java index 1b6a1f9..c5169d40 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryUnitTest.java
@@ -32,8 +32,8 @@ assertEquals(id, category.getId()); assertEquals(type, category.getType()); assertEquals(1, category.getSites().size()); - assertEquals(siteId, category.getSites().get(0).getId()); - assertEquals(title, category.getSites().get(0).getTitle()); - assertEquals(url, category.getSites().get(0).getUrl()); + assertEquals(siteId, category.getSites().get(0).getModel().get(ExploreSitesSite.ID_KEY)); + assertEquals(title, category.getSites().get(0).getModel().get(ExploreSitesSite.TITLE_KEY)); + assertEquals(url, category.getSites().get(0).getModel().get(ExploreSitesSite.URL_KEY)); } }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index abf476e..fba165d 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -8517,12 +8517,6 @@ <message name="IDS_LOCAL_DISCOVERY_ADDING_DEVICE_MESSAGE1" desc="Message for adding device number 1"> Adding the device to your account - this may take a moment... </message> - <message name="IDS_LOCAL_DISCOVERY_CONFIRM_CODE_MESSAGE" desc="Message for confirming device security code"> - Make sure the device is showing the same code. - </message> - <message name="IDS_LOCAL_DISCOVERY_CONFIRM_CODE" desc="button name to confirming security code"> - Confirm - </message> <message name="IDS_LOCAL_DISCOVERY_ERROR_OCURRED_MESSAGE" desc="Message for error page"> An error has occurred. Please check your printer and try again. </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 3f93fe26..b19bab92 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2168,6 +2168,8 @@ "android/explore_sites/get_images_task.h", "android/explore_sites/history_statistics_reporter.cc", "android/explore_sites/history_statistics_reporter.h", + "android/explore_sites/image_helper.cc", + "android/explore_sites/image_helper.h", "android/explore_sites/import_catalog_task.cc", "android/explore_sites/import_catalog_task.h", "android/explore_sites/ntp_json_fetcher.cc", @@ -2925,6 +2927,8 @@ "search/one_google_bar/one_google_bar_service_observer.h", "search/search_engine_base_url_tracker.cc", "search/search_engine_base_url_tracker.h", + "search/url_validity_checker_factory.cc", + "search/url_validity_checker_factory.h", "signin/mutable_profile_oauth2_token_service_delegate.cc", "signin/mutable_profile_oauth2_token_service_delegate.h", "signin/signin_promo.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index ffde01a..b1a05ea 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -223,6 +223,11 @@ # Needed for classic mode. "+ash/ash_service.h", ], + "platform_util_mac.mm": [ + # The following is used to forward methods to an NSWindow in another + # process, via the views::Widget API. + "+ui/views/widget/widget.h", + ], # TODO(mash): Fix. https://crbug.com/768439, https://crbug.com/768395. "exo_parts\.cc": [ "+ash/shell.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 7faa7f6f2..7d8b3fc 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2297,6 +2297,10 @@ flag_descriptions::kEnablePreviewsAndroidOmniboxUIName, flag_descriptions::kEnablePreviewsAndroidOmniboxUIDescription, kOsAndroid, FEATURE_VALUE_TYPE(previews::features::kAndroidOmniboxPreviewsBadge)}, + {"enable-lite-page-server-previews", + flag_descriptions::kEnableLitePageServerPreviewsName, + flag_descriptions::kEnableLitePageServerPreviewsDescription, kOsAndroid, + FEATURE_VALUE_TYPE(previews::features::kLitePageServerPreviews)}, #endif // OS_ANDROID {"enable-client-lo-fi", flag_descriptions::kEnableClientLoFiName, flag_descriptions::kEnableClientLoFiDescription, kOsAll, @@ -2345,6 +2349,10 @@ {"enable-system-webapps", flag_descriptions::kEnableSystemWebAppsName, flag_descriptions::kEnableSystemWebAppsDescription, kOsDesktop, FEATURE_VALUE_TYPE(features::kSystemWebApps)}, + {"enable-desktop-pwas-stay-in-window", + flag_descriptions::kDesktopPWAsStayInWindowName, + flag_descriptions::kDesktopPWAsStayInWindowDescription, kOsDesktop, + FEATURE_VALUE_TYPE(features::kDesktopPWAsStayInWindow)}, {"use-sync-sandbox", flag_descriptions::kSyncSandboxName, flag_descriptions::kSyncSandboxDescription, kOsAll, SINGLE_VALUE_TYPE_AND_VALUE(
diff --git a/chrome/browser/android/download/available_offline_content_provider.cc b/chrome/browser/android/download/available_offline_content_provider.cc index 6f5bb2d..632f26c 100644 --- a/chrome/browser/android/download/available_offline_content_provider.cc +++ b/chrome/browser/android/download/available_offline_content_provider.cc
@@ -4,6 +4,9 @@ #include "chrome/browser/android/download/available_offline_content_provider.h" +#include <memory> +#include <utility> + #include "base/base64.h" #include "base/numerics/safe_conversions.h" #include "base/strings/strcat.h" @@ -226,9 +229,10 @@ offline_items_collection::ContentId(name_space, item_id)); } -void AvailableOfflineContentProvider::LaunchDownloadsPage() { +void AvailableOfflineContentProvider::LaunchDownloadsPage( + bool open_prefetched_articles_tab) { DownloadManagerService::GetInstance()->ShowDownloadManager( - has_prefetched_content_); + open_prefetched_articles_tab); } void AvailableOfflineContentProvider::Create( @@ -268,7 +272,6 @@ break; } } - has_prefetched_content_ = summary->has_prefetched_page; // If the number of interesting items is lower then the minimum required then // reset all summary data so avoid presenting the card. @@ -289,12 +292,12 @@ // If the number of interesting items is lower then the minimum don't show any // suggestions. Otherwise trim it down to the number of expected items. size_t copied_count = end - selected.begin(); - if (copied_count == kMinInterestingItemCount && - ContentType(selected[kMinInterestingItemCount - 1]) != - AvailableContentType::kUninteresting) { - selected.resize(kMaxListItemsToReturn); - } else { + DCHECK(copied_count <= kMinInterestingItemCount); + if (copied_count < kMinInterestingItemCount || + ContentType(selected.back()) == AvailableContentType::kUninteresting) { selected.clear(); + } else { + selected.resize(kMaxListItemsToReturn); } std::vector<offline_items_collection::ContentId> selected_ids;
diff --git a/chrome/browser/android/download/available_offline_content_provider.h b/chrome/browser/android/download/available_offline_content_provider.h index 414009f..5db0b3e 100644 --- a/chrome/browser/android/download/available_offline_content_provider.h +++ b/chrome/browser/android/download/available_offline_content_provider.h
@@ -5,6 +5,9 @@ #ifndef CHROME_BROWSER_ANDROID_DOWNLOAD_AVAILABLE_OFFLINE_CONTENT_PROVIDER_H_ #define CHROME_BROWSER_ANDROID_DOWNLOAD_AVAILABLE_OFFLINE_CONTENT_PROVIDER_H_ +#include <string> +#include <vector> + #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "chrome/common/available_offline_content.mojom.h" @@ -34,7 +37,7 @@ void Summarize(SummarizeCallback) override; void LaunchItem(const std::string& item_id, const std::string& name_space) override; - void LaunchDownloadsPage() override; + void LaunchDownloadsPage(bool open_prefetched_articles_tab) override; static void Create( content::BrowserContext* browser_context, @@ -52,11 +55,6 @@ content::BrowserContext* browser_context_; - // Records if the last content fetch indicated that prefetched articles are - // available or not. - // TODO(carlosk): Directly check the existence of prefetched articles. - bool has_prefetched_content_ = false; - base::WeakPtrFactory<AvailableOfflineContentProvider> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(AvailableOfflineContentProvider);
diff --git a/chrome/browser/android/download/available_offline_content_provider_unittest.cc b/chrome/browser/android/download/available_offline_content_provider_unittest.cc index f596540..43a7445 100644 --- a/chrome/browser/android/download/available_offline_content_provider_unittest.cc +++ b/chrome/browser/android/download/available_offline_content_provider_unittest.cc
@@ -53,8 +53,6 @@ item.filter = offline_items_collection::FILTER_PAGE; item.id.id = "NonSuggestedOfflinePage"; item.id.name_space = kProviderNamespace; - // Configuring this item as being read to make sure that's not taken into - // account for filtering and prioritization. item.last_accessed_time = base::Time::Now(); return item; } @@ -72,8 +70,6 @@ // even if the test takes 1 hour to run. item.creation_time = base::Time::Now() - base::TimeDelta::FromMinutes(60 * 3.5); - // Configuring this item as being read to make sure that's not taken into - // account for filtering and prioritization. item.last_accessed_time = base::Time::Now(); return item; } @@ -129,6 +125,7 @@ class AvailableOfflineContentTest : public testing::Test { protected: void SetUp() override { + scoped_feature_list_->InitAndEnableFeature(features::kNewNetErrorPageUI); // To control the items in the aggregator, we create it and register a // single MockOfflineContentProvider. aggregator_ = static_cast<OfflineContentAggregator*>( @@ -156,14 +153,14 @@ content::TestBrowserThreadBundle thread_bundle_; TestingProfile profile_; - base::test::ScopedFeatureList scoped_feature_list_; + std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_ = + std::make_unique<base::test::ScopedFeatureList>(); OfflineContentAggregator* aggregator_; offline_items_collection::MockOfflineContentProvider content_provider_; AvailableOfflineContentProvider provider_{&profile_}; }; TEST_F(AvailableOfflineContentTest, NoContent) { - scoped_feature_list_.InitAndEnableFeature(features::kNewNetErrorPageUI); std::vector<chrome::mojom::AvailableOfflineContentPtr> suggestions = ListAndWait(); chrome::mojom::AvailableOfflineContentSummaryPtr summary = SummarizeAndWait(); @@ -177,7 +174,6 @@ } TEST_F(AvailableOfflineContentTest, TooFewInterestingItems) { - scoped_feature_list_.InitAndEnableFeature(features::kNewNetErrorPageUI); // Adds items so that we're one-ff of reaching the minimum required count so // that any extra item considered interesting would effect the results. content_provider_.SetItems({UninterestingImageItem(), OfflinePageItem(), @@ -202,7 +198,6 @@ } TEST_F(AvailableOfflineContentTest, FourInterestingItems) { - scoped_feature_list_.InitAndEnableFeature(features::kNewNetErrorPageUI); // We need at least 4 interesting items for anything to show up at all. content_provider_.SetItems({UninterestingImageItem(), VideoItem(), SuggestedOfflinePageItem(), AudioItem(), @@ -251,7 +246,8 @@ } TEST_F(AvailableOfflineContentTest, NotEnabled) { - scoped_feature_list_.InitAndDisableFeature(features::kNewNetErrorPageUI); + scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>(); + scoped_feature_list_->InitAndDisableFeature(features::kNewNetErrorPageUI); content_provider_.SetItems({SuggestedOfflinePageItem()}); std::vector<chrome::mojom::AvailableOfflineContentPtr> suggestions =
diff --git a/chrome/browser/android/explore_sites/explore_sites_bridge.cc b/chrome/browser/android/explore_sites/explore_sites_bridge.cc index e2dfde387..3edb839 100644 --- a/chrome/browser/android/explore_sites/explore_sites_bridge.cc +++ b/chrome/browser/android/explore_sites/explore_sites_bridge.cc
@@ -127,7 +127,6 @@ ExploreSitesServiceFactory::GetForBrowserContext(profile); if (!service) { DLOG(ERROR) << "Unable to create the ExploreSitesService!"; - base::android::RunObjectCallbackAndroid(j_callback_obj, nullptr); return; } @@ -175,4 +174,34 @@ Java_ExploreSitesBridge_scheduleDailyTask(env); } +float ExploreSitesBridge::GetScaleFactorFromDevice() { + JNIEnv* env = base::android::AttachCurrentThread(); + // Get scale factor from Java as a float. + return Java_ExploreSitesBridge_getScaleFactorFromDevice(env); +} + +// static +void JNI_ExploreSitesBridge_GetCategoryImage( + JNIEnv* env, + const JavaParamRef<jclass>& j_caller, + const JavaParamRef<jobject>& j_profile, + const jint j_category_id, + const jint j_pixel_size, + const JavaParamRef<jobject>& j_callback_obj) { + Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); + DCHECK(profile); + + ExploreSitesService* service = + ExploreSitesServiceFactory::GetForBrowserContext(profile); + if (!service) { + DLOG(ERROR) << "Unable to create the ExploreSitesService!"; + base::android::RunBooleanCallbackAndroid(j_callback_obj, false); + return; + } + + service->GetCategoryImage( + j_category_id, j_pixel_size, + base::BindOnce(&ImageReady, + ScopedJavaGlobalRef<jobject>(j_callback_obj))); +} } // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_bridge.h b/chrome/browser/android/explore_sites/explore_sites_bridge.h index 9de139a..98a66e5 100644 --- a/chrome/browser/android/explore_sites/explore_sites_bridge.h +++ b/chrome/browser/android/explore_sites/explore_sites_bridge.h
@@ -14,6 +14,9 @@ // The catalog update task checks that the feature is enabled and if not, // unschedules itself. static void ScheduleDailyTask(); + + // Gets the device screen scale factor from Android. + static float GetScaleFactorFromDevice(); }; } // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_fetcher.cc b/chrome/browser/android/explore_sites/explore_sites_fetcher.cc index 7adf18d6..2f80e466 100644 --- a/chrome/browser/android/explore_sites/explore_sites_fetcher.cc +++ b/chrome/browser/android/explore_sites/explore_sites_fetcher.cc
@@ -16,6 +16,7 @@ #include "base/version.h" #include "chrome/browser/android/chrome_feature_list.h" #include "chrome/browser/android/explore_sites/catalog.pb.h" +#include "chrome/browser/android/explore_sites/explore_sites_bridge.h" #include "chrome/browser/android/explore_sites/explore_sites_feature.h" #include "chrome/browser/android/explore_sites/explore_sites_types.h" #include "chrome/browser/android/explore_sites/url_util.h" @@ -153,6 +154,7 @@ max_failure_count_(is_immediate_fetch ? kMaxFailureCountForImmediateFetch : kMaxFailureCountForBackgroundFetch), + device_delegate_(std::make_unique<DeviceDelegate>()), callback_(std::move(callback)), url_loader_factory_(loader_factory), weak_factory_(this) { @@ -183,6 +185,10 @@ resource_request->headers.SetHeader("X-Client-Version", client_version_); resource_request->headers.SetHeader(net::HttpRequestHeaders::kContentType, kRequestContentType); + std::string scale_factor = + std::to_string(device_delegate_->GetScaleFactorFromDevice()); + resource_request->headers.SetHeader("X-Device-Scale-Factor", scale_factor); + if (!accept_languages_.empty()) { resource_request->headers.SetHeader( net::HttpRequestHeaders::kAcceptLanguage, accept_languages_); @@ -204,6 +210,15 @@ weak_factory_.GetWeakPtr())); } +float ExploreSitesFetcher::DeviceDelegate::GetScaleFactorFromDevice() { + return ExploreSitesBridge::GetScaleFactorFromDevice(); +} + +void ExploreSitesFetcher::SetDeviceDelegateForTest( + std::unique_ptr<ExploreSitesFetcher::DeviceDelegate> device_delegate) { + device_delegate_ = std::move(device_delegate); +} + void ExploreSitesFetcher::OnSimpleLoaderComplete( std::unique_ptr<std::string> response_body) { ExploreSitesRequestStatus status = HandleResponseCode();
diff --git a/chrome/browser/android/explore_sites/explore_sites_fetcher.h b/chrome/browser/android/explore_sites/explore_sites_fetcher.h index 8b331dd..8497d55d 100644 --- a/chrome/browser/android/explore_sites/explore_sites_fetcher.h +++ b/chrome/browser/android/explore_sites/explore_sites_fetcher.h
@@ -57,6 +57,18 @@ void disable_retry_for_testing() { disable_retry_for_testing_ = true; } + // Delegate that knows how to get data from the device. Can be overridden for + // testing. + class DeviceDelegate { + public: + DeviceDelegate() = default; + virtual ~DeviceDelegate() = default; + virtual float GetScaleFactorFromDevice(); + }; + + // Allow overriding device specific functionality for testing + void SetDeviceDelegateForTest(std::unique_ptr<DeviceDelegate> delegate); + private: explicit ExploreSitesFetcher( bool is_immediate_fetch, @@ -81,6 +93,7 @@ int max_failure_count_; bool disable_retry_for_testing_ = false; + std::unique_ptr<DeviceDelegate> device_delegate_; Callback callback_; scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
diff --git a/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc b/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc index d720b85..9cf30c1 100644 --- a/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc +++ b/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc
@@ -41,6 +41,12 @@ namespace explore_sites { +class TestingDeviceDelegate : public ExploreSitesFetcher::DeviceDelegate { + public: + TestingDeviceDelegate() = default; + float GetScaleFactorFromDevice() override { return 1.5; } +}; + // TODO(freedjm): Add tests for the headers. class ExploreSitesFetcherTest : public testing::Test { public: @@ -249,6 +255,7 @@ test_shared_url_loader_factory_, StoreResult()); if (disable_retry) fetcher->disable_retry_for_testing(); + fetcher->SetDeviceDelegateForTest(std::make_unique<TestingDeviceDelegate>()); fetcher->Start(); return fetcher; } @@ -328,6 +335,7 @@ net::HttpRequestHeaders headers = last_resource_request.headers; std::string content_type; std::string languages; + std::string scale_factor; bool success; success = headers.HasHeader("x-goog-api-key"); @@ -336,15 +344,19 @@ success = headers.HasHeader("X-Client-Version"); EXPECT_TRUE(success); + success = headers.GetHeader("X-Device-Scale-Factor", &scale_factor); + EXPECT_TRUE(success); + EXPECT_EQ(1.5, std::stof(scale_factor)); + success = headers.GetHeader(net::HttpRequestHeaders::kContentType, &content_type); EXPECT_TRUE(success); - EXPECT_EQ(content_type, "application/x-protobuf"); + EXPECT_EQ("application/x-protobuf", content_type); success = headers.GetHeader(net::HttpRequestHeaders::kAcceptLanguage, &languages); EXPECT_TRUE(success); - EXPECT_EQ(languages, kAcceptLanguages); + EXPECT_EQ(kAcceptLanguages, languages); // The finch header should not be set since the experiment is not on. success = headers.HasHeader("X-Google-Chrome-Experiment-Tag");
diff --git a/chrome/browser/android/explore_sites/explore_sites_service.h b/chrome/browser/android/explore_sites/explore_sites_service.h index c3558a3..f0ec5f7d 100644 --- a/chrome/browser/android/explore_sites/explore_sites_service.h +++ b/chrome/browser/android/explore_sites/explore_sites_service.h
@@ -23,7 +23,9 @@ // multiple site images. The site images are checked against the user // blacklist so that unwanted sites are not represented in the category image. // Returns |nullptr| if there was an error, or no match. - virtual void GetCategoryImage(int category_id, BitmapCallback callback) = 0; + virtual void GetCategoryImage(int category_id, + int pixel_size, + BitmapCallback callback) = 0; // Returns via callback the image for a site. This is typically the site // favicon. Returns |nullptr| if there was an error or no match for |site_id|.
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl.cc b/chrome/browser/android/explore_sites/explore_sites_service_impl.cc index a47e0b0..24cdb24 100644 --- a/chrome/browser/android/explore_sites/explore_sites_service_impl.cc +++ b/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
@@ -12,15 +12,10 @@ #include "chrome/browser/android/explore_sites/explore_sites_store.h" #include "chrome/browser/android/explore_sites/get_catalog_task.h" #include "chrome/browser/android/explore_sites/get_images_task.h" +#include "chrome/browser/android/explore_sites/image_helper.h" #include "chrome/browser/android/explore_sites/import_catalog_task.h" #include "components/offline_pages/task/task.h" #include "content/public/browser/browser_thread.h" -#include "content/public/common/service_manager_connection.h" -#include "services/data_decoder/public/cpp/decode_image.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/service_manager/public/cpp/connector.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/geometry/size.h" using chrome::android::explore_sites::ExploreSitesVariation; using chrome::android::explore_sites::GetExploreSitesVariation; @@ -63,19 +58,21 @@ } void ExploreSitesServiceImpl::GetCategoryImage(int category_id, + int pixel_size, BitmapCallback callback) { task_queue_.AddTask(std::make_unique<GetImagesTask>( explore_sites_store_.get(), category_id, kFaviconsPerCategoryImage, - base::BindOnce(&ExploreSitesServiceImpl::DecodeImageBytes, - std::move(callback)))); + base::BindOnce(&ExploreSitesServiceImpl::ComposeCategoryImage, + weak_ptr_factory_.GetWeakPtr(), std::move(callback), + pixel_size))); } void ExploreSitesServiceImpl::GetSiteImage(int site_id, BitmapCallback callback) { task_queue_.AddTask(std::make_unique<GetImagesTask>( explore_sites_store_.get(), site_id, - base::BindOnce(&ExploreSitesServiceImpl::DecodeImageBytes, - std::move(callback)))); + base::BindOnce(&ExploreSitesServiceImpl::ComposeSiteImage, + weak_ptr_factory_.GetWeakPtr(), std::move(callback)))); } void ExploreSitesServiceImpl::UpdateCatalogFromNetwork( @@ -127,6 +124,18 @@ AddUpdatedCatalog(catalog_version, std::move(catalog), std::move(callback)); } +void ExploreSitesServiceImpl::ComposeSiteImage(BitmapCallback callback, + EncodedImageList images) { + image_helper_.ComposeSiteImage(std::move(callback), std::move(images)); +} + +void ExploreSitesServiceImpl::ComposeCategoryImage(BitmapCallback callback, + int pixel_size, + EncodedImageList images) { + image_helper_.ComposeCategoryImage(std::move(callback), pixel_size, + std::move(images)); +} + void ExploreSitesServiceImpl::Shutdown() {} void ExploreSitesServiceImpl::OnTaskQueueIsIdle() {} @@ -142,37 +151,4 @@ explore_sites_store_.get(), version_token, std::move(catalog_proto), std::move(callback))); } - -// static -void ExploreSitesServiceImpl::OnDecodeDone(BitmapCallback callback, - const SkBitmap& decoded_image) { - DVLOG(1) << "Decoded images, result " - << (decoded_image.isNull() ? "null" : "non-null"); - std::unique_ptr<SkBitmap> bitmap = std::make_unique<SkBitmap>(decoded_image); - std::move(callback).Run(std::move(bitmap)); -} - -// static -void ExploreSitesServiceImpl::DecodeImageBytes(BitmapCallback callback, - EncodedImageList images) { - // TODO(freedjm) Fix to handle multiple images when support is added for - // creating composite images for the NTP tiles. - DVLOG(1) << "Requested decoding for " << images.size() << " images"; - if (images.size() == 0) { - std::move(callback).Run(nullptr); - return; - } - - service_manager::mojom::ConnectorRequest connector_request; - std::unique_ptr<service_manager::Connector> connector = - service_manager::Connector::Create(&connector_request); - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindConnectorRequest(std::move(connector_request)); - - data_decoder::DecodeImage(connector.get(), *images[0], - data_decoder::mojom::ImageCodec::DEFAULT, false, - data_decoder::kDefaultMaxSizeInBytes, gfx::Size(), - base::BindOnce(&OnDecodeDone, std::move(callback))); -} } // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl.h b/chrome/browser/android/explore_sites/explore_sites_service_impl.h index 46eeaa4..dcfcfd5 100644 --- a/chrome/browser/android/explore_sites/explore_sites_service_impl.h +++ b/chrome/browser/android/explore_sites/explore_sites_service_impl.h
@@ -13,6 +13,7 @@ #include "chrome/browser/android/explore_sites/explore_sites_store.h" #include "chrome/browser/android/explore_sites/explore_sites_types.h" #include "chrome/browser/android/explore_sites/history_statistics_reporter.h" +#include "chrome/browser/android/explore_sites/image_helper.h" #include "components/offline_pages/task/task_queue.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -34,8 +35,15 @@ // ExploreSitesService implementation. void GetCatalog(CatalogCallback callback) override; - void GetCategoryImage(int category_id, BitmapCallback callback) override; + void GetCategoryImage(int category_id, + int pixel_size, + BitmapCallback callback) override; + + // Compose a single site icon and return via |callback|. void GetSiteImage(int site_id, BitmapCallback callback) override; + + // Compose a category icon containing [1 - 4] site icons and return via + // |callback|. void UpdateCatalogFromNetwork(bool is_immediate_fetch, const std::string& accept_languages, BooleanCallback callback) override; @@ -51,22 +59,25 @@ std::unique_ptr<Catalog> catalog_proto, BooleanCallback callback); - static void OnDecodeDone(BitmapCallback callback, - const SkBitmap& decoded_image); - static void DecodeImageBytes(BitmapCallback callback, - EncodedImageList images); - // Callback returning from the UpdateCatalogFromNetwork operation. It // passes along the call back to the bridge and eventually back to Java land. void OnCatalogFetched(BooleanCallback callback, ExploreSitesRequestStatus status, std::unique_ptr<std::string> serialized_protobuf); + // Wrappers to call ImageHelper::Compose[Site|Category]Image. + void ComposeSiteImage(BitmapCallback callback, EncodedImageList images); + void ComposeCategoryImage(BitmapCallback callback, + int pixel_size, + EncodedImageList images); + // True when Chrome starts up, this is reset after the catalog is requested // the first time in Chrome. This prevents the ESP from changing out from // under a viewer. bool check_for_new_catalog_ = true; + ImageHelper image_helper_; + // Used to control access to the ExploreSitesStore. TaskQueue task_queue_; std::unique_ptr<ExploreSitesStore> explore_sites_store_;
diff --git a/chrome/browser/android/explore_sites/explore_sites_types.h b/chrome/browser/android/explore_sites/explore_sites_types.h index 185906c..4a16c34 100644 --- a/chrome/browser/android/explore_sites/explore_sites_types.h +++ b/chrome/browser/android/explore_sites/explore_sites_types.h
@@ -62,6 +62,7 @@ using EncodedImageBytes = std::vector<uint8_t>; using EncodedImageList = std::vector<std::unique_ptr<EncodedImageBytes>>; using EncodedImageListCallback = base::OnceCallback<void(EncodedImageList)>; +using ImageJobFinishedCallback = base::OnceCallback<void(void)>; using BitmapCallback = base::OnceCallback<void(std::unique_ptr<SkBitmap>)>;
diff --git a/chrome/browser/android/explore_sites/image_helper.cc b/chrome/browser/android/explore_sites/image_helper.cc new file mode 100644 index 0000000..5f88a0bf --- /dev/null +++ b/chrome/browser/android/explore_sites/image_helper.cc
@@ -0,0 +1,324 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/android/explore_sites/image_helper.h" + +#include "base/memory/weak_ptr.h" +#include "chrome/browser/android/explore_sites/explore_sites_types.h" +#include "content/public/common/service_manager_connection.h" +#include "services/data_decoder/public/cpp/decode_image.h" +#include "services/service_manager/public/cpp/connector.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "third_party/skia/include/core/SkPixmap.h" +#include "third_party/skia/include/core/SkRect.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/geometry/size.h" + +namespace explore_sites { +namespace { +const int kFaviconsPerCategoryImage = 4; + +// Ratio of icon size to the amount of padding between the icons. +const int kIconPaddingScale = 8; +} // namespace + +// Class Job is used to manage multiple calls to the ImageHelper. Each request +// to the ImageHelper is handled by a single Job, which is then destroyed after +// it is finished. +class ImageHelper::Job { + public: + // WARNING: When ImageJobFinishedCallback is called, |this| may be deleted. + // So nothing can be called after this callback. + Job(ImageJobType job_type, + ImageJobFinishedCallback job_finished_callback, + BitmapCallback bitmap_callback, + EncodedImageList images, + int pixel_size, + std::unique_ptr<service_manager::Connector> connector); + ~Job(); + + // Start begins the work that a Job performs (decoding and composition). + void Start(); + + void DecodeImageBytes(std::unique_ptr<EncodedImageBytes> image_bytes); + void OnDecodeSiteImageDone(const SkBitmap& decoded_image); + void OnDecodeCategoryImageDone(const SkBitmap& decoded_image); + std::unique_ptr<SkBitmap> CombineImages(); + + private: + // Used to inject connector in tests. + void SetupConnector(); + + const ImageJobType job_type_; + ImageJobFinishedCallback job_finished_callback_; + BitmapCallback bitmap_callback_; + + EncodedImageList images_; + int num_icons_, pixel_size_; + std::vector<SkBitmap> bitmaps_; + + std::unique_ptr<service_manager::Connector> connector_; + + base::WeakPtrFactory<Job> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(Job); +}; + +ImageHelper::Job::Job(ImageJobType job_type, + ImageJobFinishedCallback job_finished_callback, + BitmapCallback bitmap_callback, + EncodedImageList images, + int pixel_size, + std::unique_ptr<service_manager::Connector> connector) + : job_type_(job_type), + job_finished_callback_(std::move(job_finished_callback)), + bitmap_callback_(std::move(bitmap_callback)), + images_(std::move(images)), + pixel_size_(pixel_size), + connector_(std::move(connector)), + weak_ptr_factory_(this) { + num_icons_ = (images_.size() < kFaviconsPerCategoryImage) + ? images_.size() + : kFaviconsPerCategoryImage; +} + +ImageHelper::Job::~Job() {} + +void ImageHelper::Job::Start() { + for (int i = 0; i < num_icons_; i++) { + // TODO(freedjm): preserve order of images. + DVLOG(1) << "Decoding image " << i + 1 << " of " << images_.size(); + DecodeImageBytes(std::move(images_[i])); + } +} + +void ImageHelper::Job::SetupConnector() { + service_manager::mojom::ConnectorRequest connector_request; + connector_ = service_manager::Connector::Create(&connector_request); + content::ServiceManagerConnection::GetForProcess() + ->GetConnector() + ->BindConnectorRequest(std::move(connector_request)); +} + +void ImageHelper::Job::DecodeImageBytes( + std::unique_ptr<EncodedImageBytes> image_bytes) { + if (!connector_) { + SetupConnector(); + } + + data_decoder::mojom::ImageDecoder::DecodeImageCallback callback; + if (job_type_ == ImageJobType::kSiteIcon) { + callback = base::BindOnce(&ImageHelper::Job::OnDecodeSiteImageDone, + weak_ptr_factory_.GetWeakPtr()); + } else { + callback = base::BindOnce(&ImageHelper::Job::OnDecodeCategoryImageDone, + weak_ptr_factory_.GetWeakPtr()); + } + + data_decoder::DecodeImage(connector_.get(), *image_bytes, + data_decoder::mojom::ImageCodec::DEFAULT, false, + data_decoder::kDefaultMaxSizeInBytes, gfx::Size(), + std::move(callback)); +} + +void ImageHelper::Job::OnDecodeSiteImageDone(const SkBitmap& decoded_image) { + DVLOG(1) << "Decoded site image, result " + << (decoded_image.isNull() ? "null" : "non-null"); + + if (decoded_image.isNull()) { + std::move(bitmap_callback_).Run(nullptr); + } else { + std::move(bitmap_callback_).Run(std::make_unique<SkBitmap>(decoded_image)); + } + std::move(job_finished_callback_).Run(); +} + +void ImageHelper::Job::OnDecodeCategoryImageDone( + const SkBitmap& decoded_image) { + DVLOG(1) << "Decoded image for category, result " + << (decoded_image.isNull() ? "null" : "non-null"); + + if (decoded_image.isNull()) { + num_icons_--; + } else { + bitmaps_.push_back(decoded_image); + } + + if ((int)bitmaps_.size() == num_icons_) { // On last image for category. + std::unique_ptr<SkBitmap> category_bitmap = CombineImages(); + std::move(bitmap_callback_).Run(std::move(category_bitmap)); + std::move(job_finished_callback_).Run(); + } +} + +SkBitmap ScaleBitmap(int icon_size, SkBitmap* bitmap) { + DCHECK(bitmap); + SkBitmap temp_bitmap; + SkImageInfo scaledIconInfo = bitmap->info().makeWH(icon_size, icon_size); + temp_bitmap.setInfo(scaledIconInfo); + temp_bitmap.allocPixels(); + bool did_scale = + bitmap->pixmap().scalePixels(temp_bitmap.pixmap(), kHigh_SkFilterQuality); + if (!did_scale) { + DLOG(ERROR) << "Unable to scale icon for category image."; + return SkBitmap(); + } + return temp_bitmap; +} + +std::unique_ptr<SkBitmap> ImageHelper::Job::CombineImages() { + DVLOG(1) << "num icons: " << num_icons_; + if (num_icons_ == 0) { + return nullptr; + } + + DVLOG(1) << "pixel_size_: " << pixel_size_; + int icon_padding_pixel_size = pixel_size_ / kIconPaddingScale; + int size = pixel_size_ + icon_padding_pixel_size; + DVLOG(1) << "size: " << size; + + SkBitmap composite_bitmap; + SkImageInfo image_info = bitmaps_[0].info().makeWH(size, size); + composite_bitmap.setInfo(image_info); + composite_bitmap.allocPixels(); + composite_bitmap.eraseColor(gfx::kGoogleGrey100); // Set background to grey. + + int icon_size = pixel_size_ / 2; + + // draw icons in correct areas + switch (num_icons_) { + case 1: { + // Centered. + SkBitmap scaledBitmap = ScaleBitmap(icon_size, &bitmaps_[0]); + if (scaledBitmap.empty()) { + return nullptr; + } + composite_bitmap.writePixels(scaledBitmap.pixmap(), + (icon_size + icon_padding_pixel_size) / 2, + (icon_size + icon_padding_pixel_size) / 2); + break; + } + case 2: { + // Side by side. + for (int i = 0; i < 2; i++) { + SkBitmap scaledBitmap = ScaleBitmap(icon_size, &bitmaps_[i]); + if (scaledBitmap.empty()) { + return nullptr; + } + composite_bitmap.writePixels(scaledBitmap.pixmap(), + i * (icon_size + icon_padding_pixel_size), + (icon_size + icon_padding_pixel_size) / 2); + } + break; + } + case 3: { + // Two on top, one on bottom. + for (int i = 0; i < 3; i++) { + SkBitmap scaledBitmap = ScaleBitmap(icon_size, &bitmaps_[i]); + if (scaledBitmap.empty()) { + return nullptr; + } + switch (i) { + case 0: + composite_bitmap.writePixels(scaledBitmap.pixmap(), 0, 0); + break; + case 1: + composite_bitmap.writePixels(scaledBitmap.pixmap(), + (icon_size + icon_padding_pixel_size), + 0); + break; + default: + composite_bitmap.writePixels( + scaledBitmap.pixmap(), + (icon_size + icon_padding_pixel_size) / 2, + (icon_size + icon_padding_pixel_size)); + break; + } + } + break; + } + case 4: { + // One in each corner. + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + int index = i + 2 * j; + SkBitmap scaledBitmap = ScaleBitmap(icon_size, &bitmaps_[index]); + if (scaledBitmap.empty()) { + return nullptr; + } + composite_bitmap.writePixels( + scaledBitmap.pixmap(), j * (icon_size + icon_padding_pixel_size), + i * (icon_size + icon_padding_pixel_size)); + } + } + break; + } + default: + DLOG(ERROR) << "Invalid number of icons to combine: " << bitmaps_.size(); + return nullptr; + } + + return std::make_unique<SkBitmap>(composite_bitmap); +} + +ImageHelper::ImageHelper() : last_used_job_id_(0), weak_factory_(this) {} + +ImageHelper::~ImageHelper() {} + +void ImageHelper::NewJob( + ImageJobType job_type, + ImageJobFinishedCallback job_finished_callback, + BitmapCallback bitmap_callback, + EncodedImageList images, + int pixel_size, + std::unique_ptr<service_manager::Connector> connector) { + auto job = std::make_unique<Job>( + job_type, std::move(job_finished_callback), std::move(bitmap_callback), + std::move(images), pixel_size, std::move(connector)); + id_to_job_[last_used_job_id_] = std::move(job); + id_to_job_[last_used_job_id_]->Start(); +} + +void ImageHelper::OnJobFinished(int job_id) { + DVLOG(1) << "Erasing job " << job_id; + id_to_job_.erase(job_id); +} + +void ImageHelper::ComposeSiteImage( + BitmapCallback callback, + EncodedImageList images, + std::unique_ptr<service_manager::Connector> connector) { + DVLOG(1) << "Requested decoding for site image"; + if (images.size() == 0) { + std::move(callback).Run(nullptr); + return; + } + + NewJob(ImageJobType::kSiteIcon, + base::BindOnce(&ImageHelper::OnJobFinished, weak_factory_.GetWeakPtr(), + ++last_used_job_id_), + std::move(callback), std::move(images), -1, std::move(connector)); +} + +void ImageHelper::ComposeCategoryImage( + BitmapCallback callback, + int pixel_size, + EncodedImageList images, + std::unique_ptr<service_manager::Connector> connector) { + DVLOG(1) << "Requested decoding " << images.size() + << " images for category image"; + + if (images.size() == 0) { + std::move(callback).Run(nullptr); + return; + } + + NewJob(ImageJobType::kCategoryImage, + base::BindOnce(&ImageHelper::OnJobFinished, weak_factory_.GetWeakPtr(), + ++last_used_job_id_), + std::move(callback), std::move(images), pixel_size, + std::move(connector)); +} +} // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/image_helper.h b/chrome/browser/android/explore_sites/image_helper.h new file mode 100644 index 0000000..c410c855 --- /dev/null +++ b/chrome/browser/android/explore_sites/image_helper.h
@@ -0,0 +1,65 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ANDROID_EXPLORE_SITES_IMAGE_HELPER_H_ +#define CHROME_BROWSER_ANDROID_EXPLORE_SITES_IMAGE_HELPER_H_ + +#include <map> +#include <memory> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/android/explore_sites/explore_sites_types.h" +#include "services/service_manager/public/cpp/connector.h" +#include "third_party/skia/include/core/SkBitmap.h" + +namespace explore_sites { + +enum class ImageJobType { kSiteIcon, kCategoryImage }; + +// A helper for converting webp images to bitmaps for the frontend. +// +// The ComposeSiteImage() and ComposeCategoryImage() functions are used for +// gettting the icons for the ESP and the NTP, respectively. +class ImageHelper { + public: + ImageHelper(); + virtual ~ImageHelper(); + + // Compose a single site icon and return via |callback|. + void ComposeSiteImage( + BitmapCallback callback, + EncodedImageList images, + std::unique_ptr<service_manager::Connector> connector = nullptr); + // Compose a category icon containing [1 - 4] site icons and return via + // |callback|. + void ComposeCategoryImage( + BitmapCallback callback, + int pixel_size, + EncodedImageList images, + std::unique_ptr<service_manager::Connector> connector = nullptr); + + private: + class Job; + + void NewJob(ImageJobType job_type, + ImageJobFinishedCallback job_finished_callback, + BitmapCallback bitmap_callback, + EncodedImageList images, + int pixel_size, + std::unique_ptr<service_manager::Connector> connector); + + void OnJobFinished(int job_id); + + std::map<int, std::unique_ptr<Job>> id_to_job_; + int last_used_job_id_; + + base::WeakPtrFactory<ImageHelper> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ImageHelper); +}; + +} // namespace explore_sites + +#endif // CHROME_BROWSER_ANDROID_EXPLORE_SITES_IMAGE_HELPER_H_
diff --git a/chrome/browser/android/explore_sites/image_helper_unittest.cc b/chrome/browser/android/explore_sites/image_helper_unittest.cc new file mode 100644 index 0000000..1879177 --- /dev/null +++ b/chrome/browser/android/explore_sites/image_helper_unittest.cc
@@ -0,0 +1,277 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/android/explore_sites/image_helper.h" + +#include <memory> +#include <vector> + +#include "base/bind.h" +#include "base/test/bind_test_util.h" +#include "base/test/scoped_task_environment.h" +#include "base/test/test_simple_task_runner.h" +#include "services/data_decoder/public/cpp/test_data_decoder_service.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "ui/gfx/color_palette.h" + +namespace explore_sites { + +const std::vector<unsigned char> kWebpBytes{ + 0x52, 0x49, 0x46, 0x46, 0x40, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, + 0x56, 0x50, 0x38, 0x58, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x4c, 0x50, 0x48, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x56, 0x50, 0x38, 0x20, 0x18, 0x00, 0x00, 0x00, + 0x30, 0x01, 0x00, 0x9d, 0x01, 0x2a, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x34, 0x25, 0xa4, 0x00, 0x03, 0x70, 0x00, 0xfe, 0xfb, 0xfd, 0x50, 0x00, +}; + +std::vector<unsigned char> kInvalidWebpBytes{ + 0x52, 0x49, 0x46, 0x46, 0x40, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, + 0x50, 0x56, 0x50, 0x38, 0x58, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x4c, 0x50, +}; + +const int kIconSize = 48; +const int kPaddingScale = 8; +const int kCompositeSize = kIconSize + (kIconSize / kPaddingScale); + +// Bounds for icon size of 48. +const int kLowerBoundCenter = 14; +const int kUpperBoundCenter = 39; +const int kLowerBoundCorner = 24; +const int kUpperBoundCorner = 29; + +class ExploreSitesImageHelperTest : public testing::Test { + public: + ExploreSitesImageHelperTest() { + std::unique_ptr<service_manager::Service> service = + data_decoder::DataDecoderService::Create(); + connector_factory_ = + service_manager::TestConnectorFactory::CreateForUniqueService( + std::move(service)); + } + + ~ExploreSitesImageHelperTest() override{}; + + EncodedImageList GetEncodedImageList(int num_icons); + + BitmapCallback StoreBitmap() { + return base::BindLambdaForTesting([&](std::unique_ptr<SkBitmap> bitmap) { + last_bitmap_list.push_back(std::move(bitmap)); + }); + } + + std::vector<std::unique_ptr<SkBitmap>> last_bitmap_list; + + protected: + base::test::ScopedTaskEnvironment scoped_task_environment_; + + std::unique_ptr<service_manager::Connector> GetConnector() { + return connector_factory_->CreateConnector(); + } + + std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_; +}; + +// 1x1 webp image with color value of 0. +EncodedImageList ExploreSitesImageHelperTest::GetEncodedImageList( + int num_icons) { + EncodedImageList image_list; + for (int i = 0; i < num_icons; i++) { + image_list.push_back(std::make_unique<EncodedImageBytes>(kWebpBytes)); + } + return image_list; +} + +// Test that a single call to get a site icon works. +TEST_F(ExploreSitesImageHelperTest, TestImageHelper_SiteIcon) { + ImageHelper image_helper; + + image_helper.ComposeSiteImage(StoreBitmap(), GetEncodedImageList(1), + GetConnector()); + + scoped_task_environment_.RunUntilIdle(); + + ASSERT_NE(nullptr, last_bitmap_list[0]); + EXPECT_FALSE(last_bitmap_list[0]->isNull()); + EXPECT_EQ(last_bitmap_list[0]->width(), 1); + EXPECT_EQ(last_bitmap_list[0]->height(), 1); + EXPECT_EQ(last_bitmap_list[0]->getColor(0, 0), (unsigned)0); +} + +// Test that two sequential calls to get site icons works. +TEST_F(ExploreSitesImageHelperTest, TestImageHelper_SiteIcon_MultipleCalls) { + ImageHelper image_helper; + image_helper.ComposeSiteImage(StoreBitmap(), GetEncodedImageList(1), + GetConnector()); + scoped_task_environment_.RunUntilIdle(); + + ASSERT_NE(nullptr, last_bitmap_list[0]); + EXPECT_FALSE(last_bitmap_list[0]->isNull()); + + image_helper.ComposeSiteImage(StoreBitmap(), GetEncodedImageList(1), + GetConnector()); + scoped_task_environment_.RunUntilIdle(); + + ASSERT_NE(nullptr, last_bitmap_list[1]); + EXPECT_FALSE(last_bitmap_list[1]->isNull()); +} + +// Test that two concurrent calls to get site icons works. +TEST_F(ExploreSitesImageHelperTest, TestImageHelper_SiteIcon_ConcurrentCalls) { + ImageHelper image_helper; + image_helper.ComposeSiteImage(StoreBitmap(), GetEncodedImageList(1), + GetConnector()); + image_helper.ComposeSiteImage(StoreBitmap(), GetEncodedImageList(1), + GetConnector()); + scoped_task_environment_.RunUntilIdle(); + + ASSERT_NE(nullptr, last_bitmap_list[0]); + EXPECT_FALSE(last_bitmap_list[0]->isNull()); + ASSERT_NE(nullptr, last_bitmap_list[1]); + EXPECT_FALSE(last_bitmap_list[1]->isNull()); +} + +// Test that call to get category image with one site icon works. +TEST_F(ExploreSitesImageHelperTest, TestImageHelper_CategoryImage_One) { + ImageHelper image_helper; + image_helper.ComposeCategoryImage(StoreBitmap(), kIconSize, + GetEncodedImageList(1), GetConnector()); + scoped_task_environment_.RunUntilIdle(); + + ASSERT_NE(nullptr, last_bitmap_list[0]); + EXPECT_FALSE(last_bitmap_list[0]->isNull()); + EXPECT_EQ(last_bitmap_list[0]->width(), kCompositeSize); + EXPECT_EQ(last_bitmap_list[0]->height(), kCompositeSize); + + // One square in the center. If inside the bounds, the color should be 0. + // If outside of the bounds the color should be kGoogleGrey100. + for (int i = 0; i < last_bitmap_list[0]->width(); i++) { + for (int j = 0; j < last_bitmap_list[0]->height(); j++) { + if (j > kLowerBoundCenter && j < kUpperBoundCenter && + i > kLowerBoundCenter && + i < kUpperBoundCenter) { // centered square is color 0 + EXPECT_EQ(last_bitmap_list[0]->getColor(j, i), (unsigned)0); + } else { // rest of bitmap is grey + EXPECT_EQ(last_bitmap_list[0]->getColor(j, i), gfx::kGoogleGrey100); + } + } + } +} + +// Test that call to get category image with two site icons works. +TEST_F(ExploreSitesImageHelperTest, TestImageHelper_CategoryImage_Two) { + ImageHelper image_helper; + image_helper.ComposeCategoryImage(StoreBitmap(), kIconSize, + GetEncodedImageList(2), GetConnector()); + scoped_task_environment_.RunUntilIdle(); + + ASSERT_NE(nullptr, last_bitmap_list[0]); + EXPECT_FALSE(last_bitmap_list[0]->isNull()); + EXPECT_EQ(last_bitmap_list[0]->width(), kCompositeSize); + EXPECT_EQ(last_bitmap_list[0]->height(), kCompositeSize); + + // Two squares, side by side. If inside the bounds, the color should be 0. + // If outside of the bounds the color should be kGoogleGrey100. + for (int i = 0; i < last_bitmap_list[0]->width(); i++) { + for (int j = 0; j < last_bitmap_list[0]->height(); j++) { + if ((j < kLowerBoundCorner || j > kUpperBoundCorner) && + i > kLowerBoundCenter && i < kUpperBoundCenter) { + EXPECT_EQ(last_bitmap_list[0]->getColor(j, i), (unsigned)0); + } else { // rest of bitmap is grey + EXPECT_EQ(last_bitmap_list[0]->getColor(j, i), gfx::kGoogleGrey100); + } + } + } +} + +// Test that call to get category image with three site icons works. +TEST_F(ExploreSitesImageHelperTest, TestImageHelper_CategoryImage_Three) { + ImageHelper image_helper; + image_helper.ComposeCategoryImage(StoreBitmap(), kIconSize, + GetEncodedImageList(3), GetConnector()); + scoped_task_environment_.RunUntilIdle(); + + ASSERT_NE(nullptr, last_bitmap_list[0]); + EXPECT_FALSE(last_bitmap_list[0]->isNull()); + EXPECT_EQ(last_bitmap_list[0]->width(), kCompositeSize); + EXPECT_EQ(last_bitmap_list[0]->height(), kCompositeSize); + + // Three squares, two on top and one on bottom. If inside the bounds, the + // color should be 0. If outside of the bounds the color should be + // kGoogleGrey100. + for (int i = 0; i < last_bitmap_list[0]->width(); i++) { + for (int j = 0; j < last_bitmap_list[0]->height(); j++) { + if ((i < kLowerBoundCorner && j < kLowerBoundCorner) || // top left + (i < kLowerBoundCorner && j > kUpperBoundCorner) || // top right + (i > kUpperBoundCorner && j > kLowerBoundCenter && + j < kUpperBoundCenter)) { // bottom + EXPECT_EQ(last_bitmap_list[0]->getColor(j, i), (unsigned)0); + } else { // rest of bitmap is grey + EXPECT_EQ(last_bitmap_list[0]->getColor(j, i), gfx::kGoogleGrey100); + } + } + } +} + +// Test that call to get category image with four site icons works. +TEST_F(ExploreSitesImageHelperTest, TestImageHelper_CategoryImage_Four) { + ImageHelper image_helper; + image_helper.ComposeCategoryImage(StoreBitmap(), kIconSize, + GetEncodedImageList(4), GetConnector()); + scoped_task_environment_.RunUntilIdle(); + + ASSERT_NE(nullptr, last_bitmap_list[0]); + EXPECT_FALSE(last_bitmap_list[0]->isNull()); + EXPECT_EQ(last_bitmap_list[0]->width(), kCompositeSize); + EXPECT_EQ(last_bitmap_list[0]->height(), kCompositeSize); + + // Four squares in each corner. If inside the bounds, the color should be 0. + // If outside of the bounds the color should be kGoogleGrey100. + for (int i = 0; i < last_bitmap_list[0]->width(); i++) { + for (int j = 0; j < last_bitmap_list[0]->height(); j++) { + if ((i < kLowerBoundCorner && j < kLowerBoundCorner) || // top left + (i < kLowerBoundCorner && j > kUpperBoundCorner) || // top right + (i > kUpperBoundCorner && j < kLowerBoundCorner) || // bottom left + (i > kUpperBoundCorner && j > kUpperBoundCorner)) { // bottom right + EXPECT_EQ(last_bitmap_list[0]->getColor(j, i), (unsigned)0); + } else { // rest of bitmap is grey + EXPECT_EQ(last_bitmap_list[0]->getColor(j, i), gfx::kGoogleGrey100); + } + } + } +} + +// Test that invalid webp in the image list is ok. +TEST_F(ExploreSitesImageHelperTest, TestImageHelper_CategoryImage_InvalidWebP) { + ImageHelper image_helper; + + // Try different combinations of invalid and valid webp lists. + // Trial cases are: + // [invalid] --> nullptr result + // [invalid, valid] --> good result + for (int i = 0; i < 2; i++) { + EncodedImageList image_list; + image_list.push_back( + std::make_unique<EncodedImageBytes>(kInvalidWebpBytes)); + if (i == 1) { + image_list.push_back(std::make_unique<EncodedImageBytes>(kWebpBytes)); + } + image_helper.ComposeCategoryImage(StoreBitmap(), kIconSize, + std::move(image_list), GetConnector()); + + scoped_task_environment_.RunUntilIdle(); + + if (i == 0) { + ASSERT_EQ(nullptr, last_bitmap_list[i]); + } else { + ASSERT_NE(nullptr, last_bitmap_list[i]); + EXPECT_FALSE(last_bitmap_list[i]->isNull()); + } + } +} + +} // namespace explore_sites
diff --git a/chrome/browser/android/vr/arcore_device/arcore.h b/chrome/browser/android/vr/arcore_device/arcore.h index c9ff25a..dcd6896f 100644 --- a/chrome/browser/android/vr/arcore_device/arcore.h +++ b/chrome/browser/android/vr/arcore_device/arcore.h
@@ -15,11 +15,11 @@ namespace device { -// This allows a real or fake implementation of ARCore to +// This allows a real or fake implementation of ArCore to // be used as appropriate (i.e. for testing). -class ARCore { +class ArCore { public: - virtual ~ARCore() = default; + virtual ~ArCore() = default; // Initializes the runtime and returns whether it was successful. // If successful, the runtime must be paused when this method returns. @@ -34,7 +34,7 @@ const base::span<const float> uvs) = 0; virtual gfx::Transform GetProjectionMatrix(float near, float far) = 0; - // Update ARCore state. This call blocks for up to 1/30s while waiting for a + // Update ArCore state. This call blocks for up to 1/30s while waiting for a // new camera image. The output parameter |camera_updated| must be non-null, // the stored value indicates if the camera image was updated successfully. // The returned pose is nullptr if tracking was lost, this can happen even
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device.cc b/chrome/browser/android/vr/arcore_device/arcore_device.cc index a7fbbc56..200cf4a4 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_device.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_device.cc
@@ -67,7 +67,7 @@ } // namespace -ARCoreDevice::ARCoreDevice() +ArCoreDevice::ArCoreDevice() : VRDeviceBase(mojom::XRDeviceId::ARCORE_DEVICE_ID), main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), mailbox_bridge_(std::make_unique<vr::MailboxToSurfaceBridge>()), @@ -78,15 +78,14 @@ // TODO(https://crbug.com/836524) clean up usage of mailbox bridge // and extract the methods in this class that interact with ARCore API - // into a separate class that implements the ARCore interface. + // into a separate class that implements the ArCore interface. mailbox_bridge_->CreateUnboundContextProvider( - base::BindOnce(&ARCoreDevice::OnMailboxBridgeReady, GetWeakPtr())); + base::BindOnce(&ArCoreDevice::OnMailboxBridgeReady, GetWeakPtr())); } -ARCoreDevice::~ARCoreDevice() { -} +ArCoreDevice::~ArCoreDevice() {} -void ARCoreDevice::PauseTracking() { +void ArCoreDevice::PauseTracking() { DCHECK(IsOnMainThread()); if (is_paused_) @@ -98,10 +97,10 @@ return; PostTaskToGlThread(base::BindOnce( - &ARCoreGl::Pause, arcore_gl_thread_->GetARCoreGl()->GetWeakPtr())); + &ArCoreGl::Pause, arcore_gl_thread_->GetArCoreGl()->GetWeakPtr())); } -void ARCoreDevice::ResumeTracking() { +void ArCoreDevice::ResumeTracking() { DCHECK(IsOnMainThread()); if (!is_paused_) @@ -120,23 +119,23 @@ return; PostTaskToGlThread(base::BindOnce( - &ARCoreGl::Resume, arcore_gl_thread_->GetARCoreGl()->GetWeakPtr())); + &ArCoreGl::Resume, arcore_gl_thread_->GetArCoreGl()->GetWeakPtr())); } -void ARCoreDevice::OnMailboxBridgeReady() { +void ArCoreDevice::OnMailboxBridgeReady() { DCHECK(IsOnMainThread()); DCHECK(!arcore_gl_thread_); // MailboxToSurfaceBridge's destructor's call to DestroyContext must // happen on the GL thread, so transferring it to that thread is appropriate. // TODO(https://crbug.com/836553): use same GL thread as GVR. - arcore_gl_thread_ = std::make_unique<ARCoreGlThread>( + arcore_gl_thread_ = std::make_unique<ArCoreGlThread>( std::move(mailbox_bridge_), CreateMainThreadCallback(base::BindOnce( - &ARCoreDevice::OnARCoreGlThreadInitialized, GetWeakPtr()))); + &ArCoreDevice::OnArCoreGlThreadInitialized, GetWeakPtr()))); arcore_gl_thread_->Start(); } -void ARCoreDevice::OnARCoreGlThreadInitialized() { +void ArCoreDevice::OnArCoreGlThreadInitialized() { DCHECK(IsOnMainThread()); is_arcore_gl_thread_initialized_ = true; @@ -146,7 +145,7 @@ } } -void ARCoreDevice::RequestSession( +void ArCoreDevice::RequestSession( mojom::XRRuntimeSessionOptionsPtr options, mojom::XRRuntime::RequestSessionCallback callback) { DCHECK(IsOnMainThread()); @@ -163,7 +162,7 @@ // initialization at once on the first successful RequestSession call. if (!is_arcore_gl_thread_initialized_) { pending_request_ar_module_callback_ = - base::BindOnce(&ARCoreDevice::RequestArModule, GetWeakPtr(), + base::BindOnce(&ArCoreDevice::RequestArModule, GetWeakPtr(), options->render_process_id, options->render_frame_id, options->has_user_activation); return; @@ -173,12 +172,12 @@ options->has_user_activation); } -void ARCoreDevice::RequestArModule(int render_process_id, +void ArCoreDevice::RequestArModule(int render_process_id, int render_frame_id, bool has_user_activation) { if (arcore_java_utils_->ShouldRequestInstallArModule()) { on_request_ar_module_result_callback_ = - base::BindOnce(&ARCoreDevice::OnRequestArModuleResult, GetWeakPtr(), + base::BindOnce(&ArCoreDevice::OnRequestArModuleResult, GetWeakPtr(), render_process_id, render_frame_id, has_user_activation); arcore_java_utils_->RequestInstallArModule(); return; @@ -188,7 +187,7 @@ has_user_activation, true); } -void ARCoreDevice::OnRequestArModuleResult(int render_process_id, +void ArCoreDevice::OnRequestArModuleResult(int render_process_id, int render_frame_id, bool has_user_activation, bool success) { @@ -201,7 +200,7 @@ has_user_activation); } -void ARCoreDevice::RequestArCoreInstallOrUpdate(int render_process_id, +void ArCoreDevice::RequestArCoreInstallOrUpdate(int render_process_id, int render_frame_id, bool has_user_activation) { DCHECK(IsOnMainThread()); @@ -212,7 +211,7 @@ // ARCore is not installed or requires an update. Store the callback to be // processed later once installation/update is complete or got cancelled. on_request_arcore_install_or_update_result_callback_ = base::BindOnce( - &ARCoreDevice::OnRequestArCoreInstallOrUpdateResult, GetWeakPtr(), + &ArCoreDevice::OnRequestArCoreInstallOrUpdateResult, GetWeakPtr(), render_process_id, render_frame_id, has_user_activation); content::RenderFrameHost* render_frame_host = @@ -238,7 +237,7 @@ has_user_activation, true); } -void ARCoreDevice::OnRequestInstallArModuleResult(bool success) { +void ArCoreDevice::OnRequestInstallArModuleResult(bool success) { DCHECK(IsOnMainThread()); if (on_request_ar_module_result_callback_) { @@ -246,7 +245,7 @@ } } -void ARCoreDevice::OnRequestInstallSupportedARCoreCanceled() { +void ArCoreDevice::OnRequestInstallSupportedArCoreCanceled() { DCHECK(IsOnMainThread()); DCHECK(is_arcore_gl_thread_initialized_); DCHECK(on_request_arcore_install_or_update_result_callback_); @@ -254,7 +253,7 @@ std::move(on_request_arcore_install_or_update_result_callback_).Run(false); } -void ARCoreDevice::CallDeferredRequestSessionCallbacks(bool success) { +void ArCoreDevice::CallDeferredRequestSessionCallbacks(bool success) { DCHECK(IsOnMainThread()); DCHECK(is_arcore_gl_thread_initialized_); DCHECK(!deferred_request_session_callbacks_.empty()); @@ -283,7 +282,7 @@ deferred_request_session_callbacks_.clear(); } -void ARCoreDevice::OnRequestArCoreInstallOrUpdateResult( +void ArCoreDevice::OnRequestArCoreInstallOrUpdateResult( int render_process_id, int render_frame_id, bool has_user_activation, @@ -301,12 +300,11 @@ // ARCore sessions require camera permission. RequestCameraPermission( render_process_id, render_frame_id, has_user_activation, - base::BindOnce(&ARCoreDevice::OnRequestCameraPermissionComplete, + base::BindOnce(&ArCoreDevice::OnRequestCameraPermissionComplete, GetWeakPtr())); } -void ARCoreDevice::OnRequestCameraPermissionComplete( - bool success) { +void ArCoreDevice::OnRequestCameraPermissionComplete(bool success) { DCHECK(IsOnMainThread()); DCHECK(is_arcore_gl_thread_initialized_); @@ -319,11 +317,11 @@ RequestArCoreGlInitialization(); } -bool ARCoreDevice::ShouldPauseTrackingWhenFrameDataRestricted() { +bool ArCoreDevice::ShouldPauseTrackingWhenFrameDataRestricted() { return true; } -void ARCoreDevice::OnMagicWindowFrameDataRequest( +void ArCoreDevice::OnMagicWindowFrameDataRequest( mojom::XRFrameDataProvider::GetFrameDataCallback callback) { TRACE_EVENT0("gpu", __FUNCTION__); DCHECK(IsOnMainThread()); @@ -353,31 +351,31 @@ } PostTaskToGlThread(base::BindOnce( - &ARCoreGl::ProduceFrame, arcore_gl_thread_->GetARCoreGl()->GetWeakPtr(), + &ArCoreGl::ProduceFrame, arcore_gl_thread_->GetArCoreGl()->GetWeakPtr(), max_size, rotation, CreateMainThreadCallback(std::move(callback)))); } -void ARCoreDevice::RequestHitTest( +void ArCoreDevice::RequestHitTest( mojom::XRRayPtr ray, mojom::XREnvironmentIntegrationProvider::RequestHitTestCallback callback) { DCHECK(IsOnMainThread()); PostTaskToGlThread(base::BindOnce( - &ARCoreGl::RequestHitTest, arcore_gl_thread_->GetARCoreGl()->GetWeakPtr(), + &ArCoreGl::RequestHitTest, arcore_gl_thread_->GetArCoreGl()->GetWeakPtr(), std::move(ray), CreateMainThreadCallback(std::move(callback)))); } -void ARCoreDevice::PostTaskToGlThread(base::OnceClosure task) { +void ArCoreDevice::PostTaskToGlThread(base::OnceClosure task) { DCHECK(IsOnMainThread()); - arcore_gl_thread_->GetARCoreGl()->GetGlThreadTaskRunner()->PostTask( + arcore_gl_thread_->GetArCoreGl()->GetGlThreadTaskRunner()->PostTask( FROM_HERE, std::move(task)); } -bool ARCoreDevice::IsOnMainThread() { +bool ArCoreDevice::IsOnMainThread() { return main_thread_task_runner_->BelongsToCurrentThread(); } -void ARCoreDevice::RequestCameraPermission( +void ArCoreDevice::RequestCameraPermission( int render_process_id, int render_frame_id, bool has_user_activation, @@ -403,11 +401,11 @@ permission_manager->RequestPermission( CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, rfh, web_contents->GetURL(), has_user_activation, - base::BindRepeating(&ARCoreDevice::OnRequestCameraPermissionResult, + base::BindRepeating(&ArCoreDevice::OnRequestCameraPermissionResult, GetWeakPtr(), web_contents, base::Passed(&callback))); } -void ARCoreDevice::OnRequestCameraPermissionResult( +void ArCoreDevice::OnRequestCameraPermissionResult( content::WebContents* web_contents, base::OnceCallback<void(bool)> callback, ContentSetting content_setting) { @@ -436,7 +434,7 @@ // Show the Android camera permission info bar. PermissionUpdateInfoBarDelegate::Create( web_contents, content_settings_types, - base::BindOnce(&ARCoreDevice::OnRequestAndroidCameraPermissionResult, + base::BindOnce(&ArCoreDevice::OnRequestAndroidCameraPermissionResult, GetWeakPtr(), base::Passed(&callback))); return; case ShowPermissionInfoBarState::CANNOT_SHOW_PERMISSION_INFOBAR: @@ -447,23 +445,22 @@ NOTREACHED() << "Unknown show permission infobar state."; } -void ARCoreDevice::RequestArCoreGlInitialization() { +void ArCoreDevice::RequestArCoreGlInitialization() { DCHECK(IsOnMainThread()); DCHECK(is_arcore_gl_thread_initialized_); if (!is_arcore_gl_initialized_) { PostTaskToGlThread(base::BindOnce( - &ARCoreGl::Initialize, arcore_gl_thread_->GetARCoreGl()->GetWeakPtr(), + &ArCoreGl::Initialize, arcore_gl_thread_->GetArCoreGl()->GetWeakPtr(), CreateMainThreadCallback(base::BindOnce( - &ARCoreDevice::OnARCoreGlInitializationComplete, GetWeakPtr())))); + &ArCoreDevice::OnArCoreGlInitializationComplete, GetWeakPtr())))); return; } - OnARCoreGlInitializationComplete(true); + OnArCoreGlInitializationComplete(true); } -void ARCoreDevice::OnARCoreGlInitializationComplete( - bool success) { +void ArCoreDevice::OnArCoreGlInitializationComplete(bool success) { DCHECK(IsOnMainThread()); DCHECK(is_arcore_gl_thread_initialized_); @@ -476,13 +473,13 @@ if (!is_paused_) { PostTaskToGlThread(base::BindOnce( - &ARCoreGl::Resume, arcore_gl_thread_->GetARCoreGl()->GetWeakPtr())); + &ArCoreGl::Resume, arcore_gl_thread_->GetArCoreGl()->GetWeakPtr())); } CallDeferredRequestSessionCallbacks(/*success=*/true); } -void ARCoreDevice::OnRequestAndroidCameraPermissionResult( +void ArCoreDevice::OnRequestAndroidCameraPermissionResult( base::OnceCallback<void(bool)> callback, bool was_android_camera_permission_granted) { DCHECK(IsOnMainThread());
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device.h b/chrome/browser/android/vr/arcore_device/arcore_device.h index e87aa77..1da2bd63 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_device.h +++ b/chrome/browser/android/vr/arcore_device/arcore_device.h
@@ -28,12 +28,12 @@ namespace device { -class ARCoreGlThread; +class ArCoreGlThread; -class ARCoreDevice : public VRDeviceBase { +class ArCoreDevice : public VRDeviceBase { public: - ARCoreDevice(); - ~ARCoreDevice() override; + ArCoreDevice(); + ~ArCoreDevice() override; // VRDeviceBase implementation. void PauseTracking() override; @@ -42,12 +42,12 @@ mojom::XRRuntimeSessionOptionsPtr options, mojom::XRRuntime::RequestSessionCallback callback) override; - base::WeakPtr<ARCoreDevice> GetWeakPtr() { + base::WeakPtr<ArCoreDevice> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } void OnRequestInstallArModuleResult(bool success); - void OnRequestInstallSupportedARCoreCanceled(); + void OnRequestInstallSupportedArCoreCanceled(); private: // VRDeviceBase implementation @@ -60,7 +60,7 @@ override; void OnMailboxBridgeReady(); - void OnARCoreGlThreadInitialized(); + void OnArCoreGlThreadInitialized(); void OnRequestCameraPermissionComplete( bool success); @@ -76,7 +76,7 @@ template <typename... Args> base::OnceCallback<void(Args...)> CreateMainThreadCallback( base::OnceCallback<void(Args...)> callback) { - return base::BindOnce(&ARCoreDevice::RunCallbackOnTaskRunner<Args...>, + return base::BindOnce(&ArCoreDevice::RunCallbackOnTaskRunner<Args...>, main_thread_task_runner_, std::move(callback)); } @@ -110,12 +110,11 @@ base::OnceCallback<void(bool)> callback, bool was_android_camera_permission_granted); void RequestArCoreGlInitialization(); - void OnARCoreGlInitializationComplete( - bool success); + void OnArCoreGlInitializationComplete(bool success); scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_bridge_; - std::unique_ptr<ARCoreGlThread> arcore_gl_thread_; + std::unique_ptr<ArCoreGlThread> arcore_gl_thread_; std::unique_ptr<vr::ArCoreJavaUtils> arcore_java_utils_; bool is_arcore_gl_thread_initialized_ = false; @@ -140,8 +139,8 @@ base::OnceCallback<void(bool)> on_request_ar_module_result_callback_; // Must be last. - base::WeakPtrFactory<ARCoreDevice> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(ARCoreDevice); + base::WeakPtrFactory<ArCoreDevice> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(ArCoreDevice); }; } // namespace device
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc b/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc index 51a4e428..d816ce3 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_device_provider.cc
@@ -8,17 +8,17 @@ namespace device { -ARCoreDeviceProvider::ARCoreDeviceProvider() = default; +ArCoreDeviceProvider::ArCoreDeviceProvider() = default; -ARCoreDeviceProvider::~ARCoreDeviceProvider() = default; +ArCoreDeviceProvider::~ArCoreDeviceProvider() = default; -void ARCoreDeviceProvider::Initialize( +void ArCoreDeviceProvider::Initialize( base::RepeatingCallback<void(mojom::XRDeviceId, mojom::VRDisplayInfoPtr, mojom::XRRuntimePtr)> add_device_callback, base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback, base::OnceClosure initialization_complete) { - arcore_device_ = base::WrapUnique(new ARCoreDevice()); + arcore_device_ = base::WrapUnique(new ArCoreDevice()); add_device_callback.Run(arcore_device_->GetId(), arcore_device_->GetVRDisplayInfo(), arcore_device_->BindXRRuntimePtr()); @@ -26,7 +26,7 @@ std::move(initialization_complete).Run(); } -bool ARCoreDeviceProvider::Initialized() { +bool ArCoreDeviceProvider::Initialized() { return initialized_; }
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device_provider.h b/chrome/browser/android/vr/arcore_device/arcore_device_provider.h index 47e1f00..6e5ea79 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_device_provider.h +++ b/chrome/browser/android/vr/arcore_device/arcore_device_provider.h
@@ -12,12 +12,12 @@ namespace device { -class ARCoreDevice; +class ArCoreDevice; -class ARCoreDeviceProvider : public VRDeviceProvider { +class ArCoreDeviceProvider : public VRDeviceProvider { public: - ARCoreDeviceProvider(); - ~ARCoreDeviceProvider() override; + ArCoreDeviceProvider(); + ~ArCoreDeviceProvider() override; void Initialize( base::RepeatingCallback<void(mojom::XRDeviceId, mojom::VRDisplayInfoPtr, @@ -27,9 +27,9 @@ bool Initialized() override; private: - std::unique_ptr<ARCoreDevice> arcore_device_; + std::unique_ptr<ArCoreDevice> arcore_device_; bool initialized_ = false; - DISALLOW_COPY_AND_ASSIGN(ARCoreDeviceProvider); + DISALLOW_COPY_AND_ASSIGN(ArCoreDeviceProvider); }; } // namespace device
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc index 8ddcad9..9c3715ae 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -35,7 +35,7 @@ #include "ui/gl/init/gl_factory.h" namespace { -// Input display coordinates (range 0..1) used with ARCore's +// Input display coordinates (range 0..1) used with ArCore's // transformDisplayUvCoords to calculate the output matrix. constexpr std::array<float, 6> kDisplayCoordinatesForTransform = { 0.f, 0.f, 1.f, 0.f, 0.f, 1.f}; @@ -45,14 +45,14 @@ // screen-filling quad, origin at bottom left, u=1 at right, v=1 at top) to // camera texture UV coordinates. This matrix is used to compute texture // coordinates for copying an appropriately cropped and rotated subsection of - // the camera image. The SampleData is a bit unfortunate. ARCore doesn't + // the camera image. The SampleData is a bit unfortunate. ArCore doesn't // provide a way to get a matrix directly. There's a function to transform UV // vectors individually, which obviously can't be used from a shader, so we // run that on selected vectors and recreate the matrix from the result. // Assumes that |uvs| is the result of transforming the display coordinates // from kDisplayCoordinatesForTransform. This combines the solved matrix with - // a Y flip because ARCore's "normalized screen space" coordinates have the + // a Y flip because ArCore's "normalized screen space" coordinates have the // origin at the top left to match 2D Android APIs, so it needs a Y flip to // get an origin at bottom left as used for textures. DCHECK_EQ(uvs.size(), 6U); @@ -78,26 +78,26 @@ namespace device { -struct ARCoreHitTestRequest { - ARCoreHitTestRequest() = default; - ~ARCoreHitTestRequest() = default; +struct ArCoreHitTestRequest { + ArCoreHitTestRequest() = default; + ~ArCoreHitTestRequest() = default; mojom::XRRayPtr ray; mojom::XREnvironmentIntegrationProvider::RequestHitTestCallback callback; private: - DISALLOW_COPY_AND_ASSIGN(ARCoreHitTestRequest); + DISALLOW_COPY_AND_ASSIGN(ArCoreHitTestRequest); }; -ARCoreGl::ARCoreGl(std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_bridge) +ArCoreGl::ArCoreGl(std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_bridge) : gl_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), - arcore_(std::make_unique<ARCoreImpl>()), + arcore_(std::make_unique<ArCoreImpl>()), ar_image_transport_( std::make_unique<ARImageTransport>(std::move(mailbox_bridge))), weak_ptr_factory_(this) {} -ARCoreGl::~ARCoreGl() {} +ArCoreGl::~ArCoreGl() {} -void ARCoreGl::Initialize(base::OnceCallback<void(bool)> callback) { +void ArCoreGl::Initialize(base::OnceCallback<void(bool)> callback) { DCHECK(IsOnGlThread()); // Do not DCHECK !is_initialized to allow multiple calls to correctly @@ -116,12 +116,12 @@ } if (!arcore_->Initialize()) { - DLOG(ERROR) << "ARCore failed to initialize"; + DLOG(ERROR) << "ArCore failed to initialize"; std::move(callback).Run(false); return; } - // Set the texture on ARCore to render the camera. + // Set the texture on ArCore to render the camera. arcore_->SetCameraTexture(ar_image_transport_->GetCameraTextureId()); // Set the Geometry to ensure consistent behaviour. arcore_->SetDisplayGeometry(gfx::Size(0, 0), display::Display::ROTATE_0); @@ -131,7 +131,7 @@ std::move(callback).Run(true); } -bool ARCoreGl::InitializeGl() { +bool ArCoreGl::InitializeGl() { DCHECK(IsOnGlThread()); DCHECK(!is_initialized_); @@ -172,7 +172,7 @@ return true; } -void ARCoreGl::ProduceFrame( +void ArCoreGl::ProduceFrame( const gfx::Size& frame_size, display::Display::Rotation display_rotation, mojom::XRFrameDataProvider::GetFrameDataCallback callback) { @@ -182,7 +182,7 @@ // Check if the frame_size and display_rotation updated last frame. if (should_recalculate_uvs_) { - // Get the UV transform matrix from ARCore's UV transform. + // Get the UV transform matrix from ArCore's UV transform. std::vector<float> uvs_transformed = arcore_->TransformDisplayUvCoords(kDisplayCoordinatesForTransform); uv_transform_ = ConvertUvsToTransformMatrix(uvs_transformed); @@ -211,10 +211,10 @@ should_recalculate_uvs_ = true; } - TRACE_EVENT_BEGIN0("gpu", "ARCore Update"); + TRACE_EVENT_BEGIN0("gpu", "ArCore Update"); bool camera_updated = false; mojom::VRPosePtr pose = arcore_->Update(&camera_updated); - TRACE_EVENT_END0("gpu", "ARCore Update"); + TRACE_EVENT_END0("gpu", "ArCore Update"); if (!camera_updated) { DVLOG(1) << "arcore_->Update() failed"; std::move(callback).Run(nullptr); @@ -244,25 +244,25 @@ // on the arcore_->Update() call above, can be processed in this frame. gl_thread_task_runner_->PostTask( FROM_HERE, - base::BindOnce(&ARCoreGl::ProcessFrame, weak_ptr_factory_.GetWeakPtr(), + base::BindOnce(&ArCoreGl::ProcessFrame, weak_ptr_factory_.GetWeakPtr(), base::Passed(&frame_data), frame_size, base::Passed(&callback))); } -void ARCoreGl::RequestHitTest( +void ArCoreGl::RequestHitTest( mojom::XRRayPtr ray, mojom::XREnvironmentIntegrationProvider::RequestHitTestCallback callback) { DCHECK(IsOnGlThread()); DCHECK(is_initialized_); - std::unique_ptr<ARCoreHitTestRequest> request = - std::make_unique<ARCoreHitTestRequest>(); + std::unique_ptr<ArCoreHitTestRequest> request = + std::make_unique<ArCoreHitTestRequest>(); request->ray = std::move(ray); request->callback = std::move(callback); hit_test_requests_.push_back(std::move(request)); } -void ARCoreGl::ProcessFrame( +void ArCoreGl::ProcessFrame( mojom::XRFrameDataPtr frame_data, const gfx::Size& frame_size, mojom::XRFrameDataProvider::GetFrameDataCallback callback) { @@ -300,25 +300,25 @@ std::move(callback).Run(std::move(frame_data)); } -void ARCoreGl::Pause() { +void ArCoreGl::Pause() { DCHECK(IsOnGlThread()); DCHECK(is_initialized_); arcore_->Pause(); } -void ARCoreGl::Resume() { +void ArCoreGl::Resume() { DCHECK(IsOnGlThread()); DCHECK(is_initialized_); arcore_->Resume(); } -bool ARCoreGl::IsOnGlThread() const { +bool ArCoreGl::IsOnGlThread() const { return gl_thread_task_runner_->BelongsToCurrentThread(); } -base::WeakPtr<ARCoreGl> ARCoreGl::GetWeakPtr() { +base::WeakPtr<ArCoreGl> ArCoreGl::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.h b/chrome/browser/android/vr/arcore_device/arcore_gl.h index 00ad774..b752784 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl.h +++ b/chrome/browser/android/vr/arcore_device/arcore_gl.h
@@ -34,16 +34,16 @@ namespace device { -class ARCore; -struct ARCoreHitTestRequest; +class ArCore; +struct ArCoreHitTestRequest; class ARImageTransport; // All of this class's methods must be called on the same valid GL thread with // the exception of GetGlThreadTaskRunner() and GetWeakPtr(). -class ARCoreGl { +class ArCoreGl { public: - explicit ARCoreGl(std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_bridge); - ~ARCoreGl(); + explicit ArCoreGl(std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_bridge); + ~ArCoreGl(); void Initialize(base::OnceCallback<void(bool)> callback); @@ -61,7 +61,7 @@ mojom::XRRayPtr, mojom::XREnvironmentIntegrationProvider::RequestHitTestCallback); - base::WeakPtr<ARCoreGl> GetWeakPtr(); + base::WeakPtr<ArCoreGl> GetWeakPtr(); private: // TODO(https://crbug/835948): remove frame_size. @@ -77,7 +77,7 @@ scoped_refptr<base::SingleThreadTaskRunner> gl_thread_task_runner_; // Created on GL thread and should only be accessed on that thread. - std::unique_ptr<ARCore> arcore_; + std::unique_ptr<ArCore> arcore_; std::unique_ptr<ARImageTransport> ar_image_transport_; // Default dummy values to ensure consistent behaviour. @@ -87,18 +87,18 @@ gfx::Transform uv_transform_; gfx::Transform projection_; // The first run of ProduceFrame should set uv_transform_ and projection_ - // using the default settings in ARCore. + // using the default settings in ArCore. bool should_recalculate_uvs_ = true; bool is_initialized_ = false; vr::FPSMeter fps_meter_; - std::vector<std::unique_ptr<ARCoreHitTestRequest>> hit_test_requests_; + std::vector<std::unique_ptr<ArCoreHitTestRequest>> hit_test_requests_; // Must be last. - base::WeakPtrFactory<ARCoreGl> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(ARCoreGl); + base::WeakPtrFactory<ArCoreGl> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(ArCoreGl); }; } // namespace device
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl_thread.cc b/chrome/browser/android/vr/arcore_device/arcore_gl_thread.cc index c49c012..260ff29b7 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl_thread.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_gl_thread.cc
@@ -11,31 +11,31 @@ namespace device { -ARCoreGlThread::ARCoreGlThread( +ArCoreGlThread::ArCoreGlThread( std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_bridge, base::OnceCallback<void()> initialized_callback) - : base::android::JavaHandlerThread("ARCoreGL"), + : base::android::JavaHandlerThread("ArCoreGL"), mailbox_bridge_(std::move(mailbox_bridge)), initialized_callback_(std::move(initialized_callback)) {} -ARCoreGlThread::~ARCoreGlThread() { +ArCoreGlThread::~ArCoreGlThread() { Stop(); } -ARCoreGl* ARCoreGlThread::GetARCoreGl() { +ArCoreGl* ArCoreGlThread::GetArCoreGl() { return arcore_gl_.get(); } -void ARCoreGlThread::Init() { +void ArCoreGlThread::Init() { DCHECK(!arcore_gl_); arcore_gl_ = - std::make_unique<ARCoreGl>(base::ResetAndReturn(&mailbox_bridge_)); + std::make_unique<ArCoreGl>(base::ResetAndReturn(&mailbox_bridge_)); std::move(initialized_callback_).Run(); } -void ARCoreGlThread::CleanUp() { +void ArCoreGlThread::CleanUp() { arcore_gl_.reset(); }
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl_thread.h b/chrome/browser/android/vr/arcore_device/arcore_gl_thread.h index b28745f..95f2580 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl_thread.h +++ b/chrome/browser/android/vr/arcore_device/arcore_gl_thread.h
@@ -14,14 +14,14 @@ namespace device { -class ARCoreGl; +class ArCoreGl; -class ARCoreGlThread : public base::android::JavaHandlerThread { +class ArCoreGlThread : public base::android::JavaHandlerThread { public: - ARCoreGlThread(std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_bridge, + ArCoreGlThread(std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_bridge, base::OnceCallback<void()> initialized_callback); - ~ARCoreGlThread() override; - ARCoreGl* GetARCoreGl(); + ~ArCoreGlThread() override; + ArCoreGl* GetArCoreGl(); protected: void Init() override; @@ -32,9 +32,9 @@ base::OnceCallback<void()> initialized_callback_; // Created on GL thread. - std::unique_ptr<ARCoreGl> arcore_gl_; + std::unique_ptr<ArCoreGl> arcore_gl_; - DISALLOW_COPY_AND_ASSIGN(ARCoreGlThread); + DISALLOW_COPY_AND_ASSIGN(ArCoreGlThread); }; } // namespace device
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.cc b/chrome/browser/android/vr/arcore_device/arcore_impl.cc index f645070fa..a138f0f6 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_impl.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_impl.cc
@@ -21,13 +21,13 @@ namespace device { -ARCoreImpl::ARCoreImpl() +ArCoreImpl::ArCoreImpl() : gl_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), weak_ptr_factory_(this) {} -ARCoreImpl::~ARCoreImpl() = default; +ArCoreImpl::~ArCoreImpl() = default; -bool ARCoreImpl::Initialize() { +bool ArCoreImpl::Initialize() { DCHECK(IsOnGlThread()); DCHECK(!arcore_session_.is_valid()); @@ -35,7 +35,7 @@ JNIEnv* env = base::android::AttachCurrentThread(); if (!env) { - DLOG(ERROR) << "Unable to get JNIEnv for ARCore"; + DLOG(ERROR) << "Unable to get JNIEnv for ArCore"; return false; } @@ -48,7 +48,7 @@ } if (!vr::ArCoreJavaUtils::EnsureLoaded()) { - DLOG(ERROR) << "ARCore could not be loaded."; + DLOG(ERROR) << "ArCore could not be loaded."; return false; } @@ -97,24 +97,24 @@ return true; } -void ARCoreImpl::SetCameraTexture(GLuint camera_texture_id) { +void ArCoreImpl::SetCameraTexture(GLuint camera_texture_id) { DCHECK(IsOnGlThread()); DCHECK(arcore_session_.is_valid()); ArSession_setCameraTextureName(arcore_session_.get(), camera_texture_id); } -void ARCoreImpl::SetDisplayGeometry( +void ArCoreImpl::SetDisplayGeometry( const gfx::Size& frame_size, display::Display::Rotation display_rotation) { DCHECK(IsOnGlThread()); DCHECK(arcore_session_.is_valid()); // Display::Rotation is the same as Android's rotation and is compatible with - // what ARCore is expecting. + // what ArCore is expecting. ArSession_setDisplayGeometry(arcore_session_.get(), display_rotation, frame_size.width(), frame_size.height()); } -std::vector<float> ARCoreImpl::TransformDisplayUvCoords( +std::vector<float> ArCoreImpl::TransformDisplayUvCoords( const base::span<const float> uvs) { DCHECK(IsOnGlThread()); DCHECK(arcore_session_.is_valid()); @@ -128,7 +128,7 @@ return uvs_out; } -mojom::VRPosePtr ARCoreImpl::Update(bool* camera_updated) { +mojom::VRPosePtr ArCoreImpl::Update(bool* camera_updated) { DCHECK(IsOnGlThread()); DCHECK(arcore_session_.is_valid()); DCHECK(arcore_frame_.is_valid()); @@ -182,7 +182,7 @@ return pose; } -void ARCoreImpl::Pause() { +void ArCoreImpl::Pause() { DCHECK(IsOnGlThread()); DCHECK(arcore_session_.is_valid()); ArStatus status = ArSession_pause(arcore_session_.get()); @@ -190,7 +190,7 @@ << "ArSession_pause failed: status = " << status; } -void ARCoreImpl::Resume() { +void ArCoreImpl::Resume() { DCHECK(IsOnGlThread()); DCHECK(arcore_session_.is_valid()); ArStatus status = ArSession_resume(arcore_session_.get()); @@ -198,7 +198,7 @@ << "ArSession_resume failed: status = " << status; } -gfx::Transform ARCoreImpl::GetProjectionMatrix(float near, float far) { +gfx::Transform ArCoreImpl::GetProjectionMatrix(float near, float far) { DCHECK(IsOnGlThread()); DCHECK(arcore_session_.is_valid()); DCHECK(arcore_frame_.is_valid()); @@ -209,7 +209,7 @@ DCHECK(arcore_camera.is_valid()) << "ArFrame_acquireCamera failed despite documentation saying it cannot"; - // ARCore's projection matrix is 16 floats in column-major order. + // ArCore's projection matrix is 16 floats in column-major order. float matrix_4x4[16]; ArCamera_getProjectionMatrix(arcore_session_.get(), arcore_camera.get(), near, far, matrix_4x4); @@ -219,7 +219,7 @@ } // TODO(835948): remove image-size -bool ARCoreImpl::RequestHitTest( +bool ArCoreImpl::RequestHitTest( const mojom::XRRayPtr& ray, const gfx::Size& image_size, std::vector<mojom::XRHitResultPtr>* hit_results) { @@ -240,7 +240,7 @@ return false; } - // ARCore returns hit-results in sorted order, thus providing the guarantee + // ArCore returns hit-results in sorted order, thus providing the guarantee // of sorted results promised by the WebXR spec for requestHitTest(). ArFrame_hitTest(arcore_session_.get(), arcore_frame_.get(), screen_point.x() * image_size.width(), @@ -317,7 +317,7 @@ } // TODO(835948): remove this method. -bool ARCoreImpl::TransformRayToScreenSpace(const mojom::XRRayPtr& ray, +bool ArCoreImpl::TransformRayToScreenSpace(const mojom::XRRayPtr& ray, const gfx::Size& image_size, gfx::PointF* screen_point) { DCHECK(IsOnGlThread()); @@ -370,7 +370,7 @@ return true; } -bool ARCoreImpl::IsOnGlThread() { +bool ArCoreImpl::IsOnGlThread() { return gl_thread_task_runner_->BelongsToCurrentThread(); }
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.h b/chrome/browser/android/vr/arcore_device/arcore_impl.h index e1ccc63..55ff8b6d 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_impl.h +++ b/chrome/browser/android/vr/arcore_device/arcore_impl.h
@@ -44,7 +44,7 @@ template <> void inline ScopedGenericArObject<ArCamera*>::Free(ArCamera* ar_camera) { - // Do nothing - ArCamera has no destroy method and is managed by ARCore. + // Do nothing - ArCamera has no destroy method and is managed by ArCore. } template <> @@ -65,10 +65,10 @@ } // namespace internal // This class should be created and accessed entirely on a Gl thread. -class ARCoreImpl : public ARCore { +class ArCoreImpl : public ArCore { public: - ARCoreImpl(); - ~ARCoreImpl() override; + ArCoreImpl(); + ~ArCoreImpl() override; bool Initialize() override; void SetDisplayGeometry(const gfx::Size& frame_size, @@ -90,21 +90,21 @@ gfx::PointF* screen_point); bool IsOnGlThread(); - base::WeakPtr<ARCoreImpl> GetWeakPtr() { + base::WeakPtr<ArCoreImpl> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } scoped_refptr<base::SingleThreadTaskRunner> gl_thread_task_runner_; - // An ARCore session, which is distinct and independent of XRSessions. + // An ArCore session, which is distinct and independent of XRSessions. // There will only ever be one in Chrome even when supporting // multiple XRSessions. internal::ScopedArCoreObject<ArSession*> arcore_session_; internal::ScopedArCoreObject<ArFrame*> arcore_frame_; // Must be last. - base::WeakPtrFactory<ARCoreImpl> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(ARCoreImpl); + base::WeakPtrFactory<ArCoreImpl> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(ArCoreImpl); }; } // namespace device
diff --git a/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc b/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc index e111d09..e8c6531 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc
@@ -31,7 +31,7 @@ return LoadArCoreSdk(base::android::ConvertJavaStringToUTF8(env, java_path)); } -ArCoreJavaUtils::ArCoreJavaUtils(device::ARCoreDevice* arcore_device) +ArCoreJavaUtils::ArCoreJavaUtils(device::ArCoreDevice* arcore_device) : arcore_device_(arcore_device) { DCHECK(arcore_device_); @@ -53,7 +53,7 @@ void ArCoreJavaUtils::OnRequestInstallSupportedArCoreCanceled( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj) { - arcore_device_->OnRequestInstallSupportedARCoreCanceled(); + arcore_device_->OnRequestInstallSupportedArCoreCanceled(); } bool ArCoreJavaUtils::ShouldRequestInstallArModule() {
diff --git a/chrome/browser/android/vr/arcore_device/arcore_java_utils.h b/chrome/browser/android/vr/arcore_device/arcore_java_utils.h index dcd87dd7..10619956 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_java_utils.h +++ b/chrome/browser/android/vr/arcore_device/arcore_java_utils.h
@@ -10,7 +10,7 @@ #include "base/memory/weak_ptr.h" namespace device { -class ARCoreDevice; +class ArCoreDevice; } namespace vr { @@ -19,7 +19,7 @@ public: static base::android::ScopedJavaLocalRef<jobject> GetApplicationContext(); static bool EnsureLoaded(); - explicit ArCoreJavaUtils(device::ARCoreDevice* arcore_device); + explicit ArCoreJavaUtils(device::ArCoreDevice* arcore_device); ~ArCoreJavaUtils(); bool ShouldRequestInstallArModule(); void RequestInstallArModule(); @@ -37,7 +37,7 @@ const base::android::JavaParamRef<jobject>& obj); private: - device::ARCoreDevice* arcore_device_; + device::ArCoreDevice* arcore_device_; base::android::ScopedJavaGlobalRef<jobject> j_arcore_java_utils_; };
diff --git a/chrome/browser/android/vr/arcore_device/fake_arcore.cc b/chrome/browser/android/vr/arcore_device/fake_arcore.cc index 1b7eccb3..02fffd4 100644 --- a/chrome/browser/android/vr/arcore_device/fake_arcore.cc +++ b/chrome/browser/android/vr/arcore_device/fake_arcore.cc
@@ -13,17 +13,17 @@ namespace device { -FakeARCore::FakeARCore() +FakeArCore::FakeArCore() : gl_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} -FakeARCore::~FakeARCore() = default; +FakeArCore::~FakeArCore() = default; -bool FakeARCore::Initialize() { +bool FakeArCore::Initialize() { DCHECK(IsOnGlThread()); return true; } -void FakeARCore::SetDisplayGeometry( +void FakeArCore::SetDisplayGeometry( const gfx::Size& frame_size, display::Display::Rotation display_rotation) { DCHECK(IsOnGlThread()); @@ -31,9 +31,9 @@ frame_size_ = frame_size; } -void FakeARCore::SetCameraTexture(GLuint texture) { +void FakeArCore::SetCameraTexture(GLuint texture) { DCHECK(IsOnGlThread()); - // We need a GL_TEXTURE_EXTERNAL_OES to be compatible with the real ARCore. + // We need a GL_TEXTURE_EXTERNAL_OES to be compatible with the real ArCore. // The content doesn't really matter, just create an AHardwareBuffer-backed // GLImage and bind it to the texture. @@ -116,19 +116,19 @@ glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); } -std::vector<float> FakeARCore::TransformDisplayUvCoords( +std::vector<float> FakeArCore::TransformDisplayUvCoords( const base::span<const float> uvs) { - // Try to match ARCore's transfore values. + // Try to match ArCore's transfore values. // - // Sample ARCore input: width=1080, height=1795, rotation=0, + // Sample ArCore input: width=1080, height=1795, rotation=0, // vecs = (0, 0), (0, 1), (1, 0), (1, 1) - // Sample ARCore output: + // Sample ArCore output: // (0.0325544, 1, // 0.967446, 1, // 0.0325543, 0, // 0.967446, 1.19209e-07) // - // FakeARCoreDriver test_arcore; + // FakeArCoreDriver test_arcore; // test_arcore.SetCameraAspect(16.f / 9.f); // test_arcore.SetDisplayGeometry(0, 1080, 1795); // float in[8] = {0, 0, 0, 1, 1, 0, 1, 1}; @@ -221,12 +221,12 @@ return uvs_out; } -gfx::Transform FakeARCore::GetProjectionMatrix(float near, float far) { +gfx::Transform FakeArCore::GetProjectionMatrix(float near, float far) { DCHECK(IsOnGlThread()); // Get a projection matrix matching the current screen orientation and // aspect. Currently, this uses a hardcoded FOV angle for the smaller screen // dimension, and adjusts the other angle to preserve the aspect. A better - // simulation of ARCore should apply cropping to the underlying fixed-aspect + // simulation of ArCore should apply cropping to the underlying fixed-aspect // simulated camera image. constexpr float fov_half_angle_degrees = 30.f; float base_tan = tanf(fov_half_angle_degrees * base::kPiFloat / 180.f); @@ -253,7 +253,7 @@ return result; } -mojom::VRPosePtr FakeARCore::Update(bool* camera_updated) { +mojom::VRPosePtr FakeArCore::Update(bool* camera_updated) { DCHECK(IsOnGlThread()); DCHECK(camera_updated); @@ -274,7 +274,7 @@ return pose; } -bool FakeARCore::RequestHitTest( +bool FakeArCore::RequestHitTest( const mojom::XRRayPtr& ray, const gfx::Size& image_size, std::vector<mojom::XRHitResultPtr>* hit_results) { @@ -282,15 +282,15 @@ return false; } -void FakeARCore::Pause() { +void FakeArCore::Pause() { DCHECK(IsOnGlThread()); } -void FakeARCore::Resume() { +void FakeArCore::Resume() { DCHECK(IsOnGlThread()); } -bool FakeARCore::IsOnGlThread() const { +bool FakeArCore::IsOnGlThread() const { return gl_thread_task_runner_->BelongsToCurrentThread(); }
diff --git a/chrome/browser/android/vr/arcore_device/fake_arcore.h b/chrome/browser/android/vr/arcore_device/fake_arcore.h index a7fc8f6b..70531e6 100644 --- a/chrome/browser/android/vr/arcore_device/fake_arcore.h +++ b/chrome/browser/android/vr/arcore_device/fake_arcore.h
@@ -17,15 +17,15 @@ namespace device { -// Minimal fake ARCore implementation for testing. It can populate +// Minimal fake ArCore implementation for testing. It can populate // the camera texture with a GL_TEXTURE_OES image and do UV transform // calculations. -class FakeARCore : public ARCore { +class FakeArCore : public ArCore { public: - FakeARCore(); - ~FakeARCore() override; + FakeArCore(); + ~FakeArCore() override; - // ARCoreDriverBase implementation. + // ArCoreDriverBase implementation. bool Initialize() override; void SetCameraTexture(GLuint texture) override; void SetDisplayGeometry(const gfx::Size& frame_size, @@ -55,7 +55,7 @@ // Storage for the testing placeholder image to keep it alive. scoped_refptr<gl::GLImageAHardwareBuffer> placeholder_camera_image_; - DISALLOW_COPY_AND_ASSIGN(FakeARCore); + DISALLOW_COPY_AND_ASSIGN(FakeArCore); }; } // namespace device
diff --git a/chrome/browser/android/vr/vr_shell_delegate.cc b/chrome/browser/android/vr/vr_shell_delegate.cc index c6c75e9..252e289d 100644 --- a/chrome/browser/android/vr/vr_shell_delegate.cc +++ b/chrome/browser/android/vr/vr_shell_delegate.cc
@@ -53,20 +53,20 @@ } #if BUILDFLAG(ENABLE_ARCORE) -class ARCoreDeviceProviderFactoryImpl - : public device::ARCoreDeviceProviderFactory { +class ArCoreDeviceProviderFactoryImpl + : public device::ArCoreDeviceProviderFactory { public: - ARCoreDeviceProviderFactoryImpl() = default; - ~ARCoreDeviceProviderFactoryImpl() override = default; + ArCoreDeviceProviderFactoryImpl() = default; + ~ArCoreDeviceProviderFactoryImpl() override = default; std::unique_ptr<device::VRDeviceProvider> CreateDeviceProvider() override; private: - DISALLOW_COPY_AND_ASSIGN(ARCoreDeviceProviderFactoryImpl); + DISALLOW_COPY_AND_ASSIGN(ArCoreDeviceProviderFactoryImpl); }; std::unique_ptr<device::VRDeviceProvider> -ARCoreDeviceProviderFactoryImpl::CreateDeviceProvider() { - return std::make_unique<device::ARCoreDeviceProvider>(); +ArCoreDeviceProviderFactoryImpl::CreateDeviceProvider() { + return std::make_unique<device::ArCoreDeviceProvider>(); } #endif @@ -354,8 +354,8 @@ #if BUILDFLAG(ENABLE_ARCORE) // TODO(https://crbug.com/837965): Move this to an ARCore-specific location // with similar timing (occurs before XRRuntimeManager is initialized). - device::ARCoreDeviceProviderFactory::Install( - std::make_unique<ARCoreDeviceProviderFactoryImpl>()); + device::ArCoreDeviceProviderFactory::Install( + std::make_unique<ArCoreDeviceProviderFactoryImpl>()); #endif }
diff --git a/chrome/browser/apps/platform_apps/api/BUILD.gn b/chrome/browser/apps/platform_apps/api/BUILD.gn index 066162a..85842d0e 100644 --- a/chrome/browser/apps/platform_apps/api/BUILD.gn +++ b/chrome/browser/apps/platform_apps/api/BUILD.gn
@@ -45,6 +45,7 @@ "//chrome/browser/apps/platform_apps/api/music_manager_private", "//chrome/browser/extensions", "//chrome/common", + "//chrome/common/apps/platform_apps", "//chrome/common/apps/platform_apps/api", "//chrome/services/media_gallery_util/public/cpp", "//components/storage_monitor",
diff --git a/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_api.cc b/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_api.cc index 1fd3b9b..d99a297 100644 --- a/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_api.cc +++ b/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_api.cc
@@ -37,6 +37,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/chrome_select_file_policy.h" #include "chrome/common/apps/platform_apps/api/media_galleries.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "chrome/services/media_gallery_util/public/cpp/safe_media_metadata_parser.h" @@ -60,7 +61,6 @@ #include "extensions/browser/extension_system.h" #include "extensions/common/extension.h" #include "extensions/common/permissions/api_permission.h" -#include "extensions/common/permissions/media_galleries_permission.h" #include "extensions/common/permissions/permissions_data.h" #include "net/base/mime_sniffer.h" #include "storage/browser/blob/blob_data_handle.h" @@ -152,18 +152,18 @@ if (!rfh) return NULL; - extensions::MediaGalleriesPermission::CheckParam read_param( - extensions::MediaGalleriesPermission::kReadPermission); + MediaGalleriesPermission::CheckParam read_param( + MediaGalleriesPermission::kReadPermission); const extensions::PermissionsData* permissions_data = extension->permissions_data(); bool has_read_permission = permissions_data->CheckAPIPermissionWithParam( extensions::APIPermission::kMediaGalleries, &read_param); - extensions::MediaGalleriesPermission::CheckParam copy_to_param( - extensions::MediaGalleriesPermission::kCopyToPermission); + MediaGalleriesPermission::CheckParam copy_to_param( + MediaGalleriesPermission::kCopyToPermission); bool has_copy_to_permission = permissions_data->CheckAPIPermissionWithParam( extensions::APIPermission::kMediaGalleries, ©_to_param); - extensions::MediaGalleriesPermission::CheckParam delete_param( - extensions::MediaGalleriesPermission::kDeletePermission); + MediaGalleriesPermission::CheckParam delete_param( + MediaGalleriesPermission::kDeletePermission); bool has_delete_permission = permissions_data->CheckAPIPermissionWithParam( extensions::APIPermission::kMediaGalleries, &delete_param);
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc index 4f3936d..74142660 100644 --- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc +++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -36,6 +36,8 @@ #include "components/history/core/browser/history_service.h" #include "components/omnibox/browser/autocomplete_classifier.h" #include "components/omnibox/browser/autocomplete_match.h" +#include "components/omnibox/browser/omnibox_field_trial.h" +#include "components/omnibox/browser/omnibox_pedal_provider.h" #include "components/prefs/pref_service.h" #include "components/signin/core/browser/signin_manager.h" #include "components/unified_consent/unified_consent_service.h" @@ -95,7 +97,11 @@ NewPersonalizedDataCollectionConsentHelper( ProfileSyncServiceFactory::GetSyncServiceForBrowserContext( profile_))), - storage_partition_(nullptr) {} + storage_partition_(nullptr) { + if (OmniboxFieldTrial::GetPedalSuggestionMode() != + OmniboxFieldTrial::PedalSuggestionMode::NONE) + pedal_provider_ = std::make_unique<OmniboxPedalProvider>(); +} ChromeAutocompleteProviderClient::~ChromeAutocompleteProviderClient() { } @@ -169,6 +175,15 @@ create_if_necessary); } +OmniboxPedalProvider* ChromeAutocompleteProviderClient::GetPedalProvider() + const { + // If Pedals are disabled, we should never get here to use the provider. + DCHECK_NE(OmniboxFieldTrial::GetPedalSuggestionMode(), + OmniboxFieldTrial::PedalSuggestionMode::NONE); + DCHECK(pedal_provider_); + return pedal_provider_.get(); +} + scoped_refptr<ShortcutsBackend> ChromeAutocompleteProviderClient::GetShortcutsBackend() { return ShortcutsBackendFactory::GetForProfile(profile_);
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h index 6eda7d2..23e917a 100644 --- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h +++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
@@ -40,6 +40,7 @@ bool create_if_necessary) const override; DocumentSuggestionsService* GetDocumentSuggestionsService( bool create_if_necessary) const override; + OmniboxPedalProvider* GetPedalProvider() const override; scoped_refptr<ShortcutsBackend> GetShortcutsBackend() override; scoped_refptr<ShortcutsBackend> GetShortcutsBackendIfExists() override; std::unique_ptr<KeywordExtensionsDelegate> GetKeywordExtensionsDelegate( @@ -86,6 +87,7 @@ private: Profile* profile_; ChromeAutocompleteSchemeClassifier scheme_classifier_; + std::unique_ptr<OmniboxPedalProvider> pedal_provider_; std::unique_ptr<unified_consent::UrlKeyedDataCollectionConsentHelper> url_consent_helper_;
diff --git a/chrome/browser/autofill/strike_database_factory.cc b/chrome/browser/autofill/strike_database_factory.cc index c21d418..4972606 100644 --- a/chrome/browser/autofill/strike_database_factory.cc +++ b/chrome/browser/autofill/strike_database_factory.cc
@@ -40,9 +40,4 @@ profile->GetPath().Append(FILE_PATH_LITERAL("AutofillStrikeDatabase"))); } -content::BrowserContext* StrikeDatabaseFactory::GetBrowserContextToUse( - content::BrowserContext* context) const { - return chrome::GetBrowserContextRedirectedInIncognito(context); -} - } // namespace autofill
diff --git a/chrome/browser/autofill/strike_database_factory.h b/chrome/browser/autofill/strike_database_factory.h index 5e93e11..60e2959 100644 --- a/chrome/browser/autofill/strike_database_factory.h +++ b/chrome/browser/autofill/strike_database_factory.h
@@ -38,8 +38,6 @@ // BrowserContextKeyedServiceFactory: KeyedService* BuildServiceInstanceFor( content::BrowserContext* profile) const override; - content::BrowserContext* GetBrowserContextToUse( - content::BrowserContext* context) const override; DISALLOW_COPY_AND_ASSIGN(StrikeDatabaseFactory); };
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index d86ddd51..a621529 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -89,6 +89,7 @@ <structure name="IDR_NUX_SET_AS_DEFAULT_PROXY_HTML" file="resources\welcome\onboarding_welcome\set_as_default\nux_set_as_default_proxy.html" type="chrome_html" /> <structure name="IDR_NUX_SET_AS_DEFAULT_PROXY_JS" file="resources\welcome\onboarding_welcome\set_as_default\nux_set_as_default_proxy.js" type="chrome_html" /> <structure name="IDR_NUX_CHOOSER_SHARED_CSS" file="resources\welcome\onboarding_welcome\shared\chooser_shared_css.html" type="chrome_html" /> + <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_I18N_SETUP_HTML" file="resources\welcome\onboarding_welcome\shared\i18n_setup.html" type="chrome_html" /> </if> <if expr="is_win"> <structure name="IDR_WELCOME_WIN10_CSS" file="resources\welcome\welcome_win10.css" type="chrome_html" /> @@ -260,8 +261,6 @@ <include name="IDR_MD_BOOKMARKS_DEBOUNCER_JS" file="resources\md_bookmarks\debouncer.js" type="BINDATA" /> <include name="IDR_MD_BOOKMARKS_DIALOG_FOCUS_MANAGER_HTML" file="resources\md_bookmarks\dialog_focus_manager.html" type="BINDATA" /> <include name="IDR_MD_BOOKMARKS_DIALOG_FOCUS_MANAGER_JS" file="resources\md_bookmarks\dialog_focus_manager.js" type="BINDATA" /> - <include name="IDR_MD_BOOKMARKS_DND_CHIP_HTML" file="resources\md_bookmarks\dnd_chip.html" type="BINDATA" /> - <include name="IDR_MD_BOOKMARKS_DND_CHIP_JS" file="resources\md_bookmarks\dnd_chip.js" type="BINDATA" /> <include name="IDR_MD_BOOKMARKS_DND_MANAGER_HTML" file="resources\md_bookmarks\dnd_manager.html" type="BINDATA" /> <include name="IDR_MD_BOOKMARKS_DND_MANAGER_JS" file="resources\md_bookmarks\dnd_manager.js" type="BINDATA" /> <include name="IDR_MD_BOOKMARKS_EDIT_DIALOG_HTML" file="resources\md_bookmarks\edit_dialog.html" type="BINDATA" />
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index aa5f263..335f1f4 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -4004,7 +4004,11 @@ MaybeCreateThrottleFor(handle); if (bookmark_app_experimental_throttle) throttles.push_back(std::move(bookmark_app_experimental_throttle)); - } else { + } else if (!base::FeatureList::IsEnabled( + features::kDesktopPWAsStayInWindow)) { + // Only add the bookmark app navigation throttle if the stay in + // window flag is not set, as the navigation throttle controls + // opening out of scope links in the browser. auto bookmark_app_throttle = extensions::BookmarkAppNavigationThrottle::MaybeCreateThrottleFor( handle);
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index f2d4129..892dbad 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -393,6 +393,8 @@ "arc/auth/arc_robot_auth_code_fetcher.h", "arc/bluetooth/arc_bluetooth_bridge.cc", "arc/bluetooth/arc_bluetooth_bridge.h", + "arc/bluetooth/arc_bluetooth_task_queue.cc", + "arc/bluetooth/arc_bluetooth_task_queue.h", "arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc", "arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h", "arc/boot_phase_monitor/arc_instance_throttle.cc", @@ -1968,6 +1970,8 @@ "app_mode/test_kiosk_extension_builder.h", "crostini/crostini_test_helper.cc", "crostini/crostini_test_helper.h", + "drive/drivefs_test_support.cc", + "drive/drivefs_test_support.h", "extensions/test_external_cache.cc", "extensions/test_external_cache.h", "lock_screen_apps/fake_lock_screen_profile_creator.cc", @@ -1998,7 +2002,10 @@ ":chromeos", "//chrome/test:test_support", "//chromeos", + "//chromeos/components/drivefs", + "//chromeos/components/drivefs:test_support", "//components/crx_file", + "//components/drive", "//components/policy/proto", "//crypto:platform", "//google_apis", @@ -2040,6 +2047,7 @@ "arc/arc_support_host_unittest.cc", "arc/arc_util_unittest.cc", "arc/bluetooth/arc_bluetooth_bridge_unittest.cc", + "arc/bluetooth/arc_bluetooth_task_queue_unittest.cc", "arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc", "arc/downloads_watcher/arc_downloads_watcher_service_unittest.cc", "arc/extensions/arc_support_message_host_unittest.cc",
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc index b0faf95..fa71541 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
@@ -192,13 +192,7 @@ } base::Version GetPlatformVersion() { - int32_t major_version; - int32_t minor_version; - int32_t bugfix_version; - base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, - &bugfix_version); - return base::Version(base::StringPrintf("%d.%d.%d", major_version, - minor_version, bugfix_version)); + return base::Version(base::SysInfo::OperatingSystemVersion()); } // Converts a flag constant to actual command line switch value.
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc index e15f884..65e8c215 100644 --- a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc +++ b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
@@ -327,11 +327,16 @@ auto enrollment_token_fetcher = std::make_unique<ArcActiveDirectoryEnrollmentTokenFetcher>( ArcSessionManager::Get()->support_host()); - enrollment_token_fetcher->Fetch( + + // Add the request to |pending_token_requests_| first, before starting a + // token fetch. In case the callback is called immediately, we do not want + // to add an already completed request to |pending_token_requests_|. + auto* enrollment_token_fetcher_ptr = enrollment_token_fetcher.get(); + pending_token_requests_.emplace_back(std::move(enrollment_token_fetcher)); + enrollment_token_fetcher_ptr->Fetch( base::BindOnce(&ArcAuthService::OnActiveDirectoryEnrollmentTokenFetched, weak_ptr_factory_.GetWeakPtr(), - enrollment_token_fetcher.get(), std::move(callback))); - pending_token_requests_.emplace_back(std::move(enrollment_token_fetcher)); + enrollment_token_fetcher_ptr, std::move(callback))); return; } @@ -358,11 +363,16 @@ auth_code_fetcher = CreateArcBackgroundAuthCodeFetcher( signin_manager->GetAuthenticatedAccountId(), initial_signin); } - auth_code_fetcher->Fetch( - base::BindOnce(&ArcAuthService::OnPrimaryAccountAuthCodeFetched, - weak_ptr_factory_.GetWeakPtr(), auth_code_fetcher.get(), - std::move(callback))); + + // Add the request to |pending_token_requests_| first, before starting a token + // fetch. In case the callback is called immediately, we do not want to add an + // already completed request to |pending_token_requests_|. + auto* auth_code_fetcher_ptr = auth_code_fetcher.get(); pending_token_requests_.emplace_back(std::move(auth_code_fetcher)); + auth_code_fetcher_ptr->Fetch( + base::BindOnce(&ArcAuthService::OnPrimaryAccountAuthCodeFetched, + weak_ptr_factory_.GetWeakPtr(), auth_code_fetcher_ptr, + std::move(callback))); } void ArcAuthService::OnTokenUpserted(
diff --git a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc index 5e4a03dd..430a3a7 100644 --- a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc +++ b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.cc
@@ -1197,6 +1197,11 @@ } void ArcBluetoothBridge::StartDiscovery() { + discovery_queue_.Push(base::BindOnce(&ArcBluetoothBridge::StartDiscoveryImpl, + weak_factory_.GetWeakPtr(), false)); +} + +void ArcBluetoothBridge::StartDiscoveryImpl(bool le_scan) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(bluetooth_adapter_); @@ -1206,10 +1211,14 @@ base::Bind(&ArcBluetoothBridge::CancelDiscovery, weak_factory_.GetWeakPtr())); SendCachedDevicesFound(); + discovery_queue_.Pop(); return; } - bluetooth_adapter_->StartDiscoverySession( + bluetooth_adapter_->StartDiscoverySessionWithFilter( + le_scan ? std::make_unique<BluetoothDiscoveryFilter>( + device::BLUETOOTH_TRANSPORT_LE) + : nullptr, base::Bind(&ArcBluetoothBridge::OnDiscoveryStarted, weak_factory_.GetWeakPtr()), base::Bind(&ArcBluetoothBridge::OnDiscoveryError, @@ -1217,14 +1226,20 @@ } void ArcBluetoothBridge::CancelDiscovery() { - if (!discovery_session_) { - return; - } + discovery_queue_.Push(base::BindOnce(&ArcBluetoothBridge::CancelDiscoveryImpl, + weak_factory_.GetWeakPtr())); +} - discovery_session_->Stop(base::Bind(&ArcBluetoothBridge::OnDiscoveryStopped, - weak_factory_.GetWeakPtr()), - base::Bind(&ArcBluetoothBridge::OnDiscoveryError, - weak_factory_.GetWeakPtr())); +void ArcBluetoothBridge::CancelDiscoveryImpl() { + discovery_off_timer_.Stop(); + discovery_session_.reset(); + auto* bluetooth_instance = ARC_GET_INSTANCE_FOR_METHOD( + arc_bridge_service_->bluetooth(), OnDiscoveryStateChanged); + if (bluetooth_instance != nullptr) { + bluetooth_instance->OnDiscoveryStateChanged( + mojom::BluetoothDiscoveryState::STOPPED); + } + discovery_queue_.Pop(); } void ArcBluetoothBridge::OnPoweredOn( @@ -1260,37 +1275,22 @@ std::unique_ptr<BluetoothDiscoverySession> session) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - auto* bluetooth_instance = ARC_GET_INSTANCE_FOR_METHOD( - arc_bridge_service_->bluetooth(), OnDiscoveryStateChanged); - if (!bluetooth_instance) - return; - - discovery_session_ = std::move(session); - // We need to set timer to turn device discovery off because of the difference // between Android API (do device discovery once) and Chrome API (do device // discovery until user turns it off). discovery_off_timer_.Start(FROM_HERE, kDiscoveryTimeout, base::Bind(&ArcBluetoothBridge::CancelDiscovery, weak_factory_.GetWeakPtr())); + discovery_session_ = std::move(session); - bluetooth_instance->OnDiscoveryStateChanged( - mojom::BluetoothDiscoveryState::STARTED); - - SendCachedDevicesFound(); -} - -void ArcBluetoothBridge::OnDiscoveryStopped() { auto* bluetooth_instance = ARC_GET_INSTANCE_FOR_METHOD( arc_bridge_service_->bluetooth(), OnDiscoveryStateChanged); - if (!bluetooth_instance) - return; - - discovery_session_.reset(); - discovery_off_timer_.Stop(); - - bluetooth_instance->OnDiscoveryStateChanged( - mojom::BluetoothDiscoveryState::STOPPED); + if (bluetooth_instance != nullptr) { + bluetooth_instance->OnDiscoveryStateChanged( + mojom::BluetoothDiscoveryState::STARTED); + SendCachedDevicesFound(); + } + discovery_queue_.Pop(); } void ArcBluetoothBridge::CreateBond(mojom::BluetoothAddressPtr addr, @@ -1363,19 +1363,8 @@ } void ArcBluetoothBridge::StartLEScan() { - DCHECK(bluetooth_adapter_); - if (discovery_session_) { - LOG(WARNING) << "Discovery session already running; leaving alone"; - SendCachedDevicesFound(); - return; - } - bluetooth_adapter_->StartDiscoverySessionWithFilter( - std::make_unique<BluetoothDiscoveryFilter>( - device::BLUETOOTH_TRANSPORT_LE), - base::Bind(&ArcBluetoothBridge::OnDiscoveryStarted, - weak_factory_.GetWeakPtr()), - base::Bind(&ArcBluetoothBridge::OnDiscoveryError, - weak_factory_.GetWeakPtr())); + discovery_queue_.Push(base::BindOnce(&ArcBluetoothBridge::StartDiscoveryImpl, + weak_factory_.GetWeakPtr(), true)); } void ArcBluetoothBridge::StopLEScan() { @@ -2183,31 +2172,6 @@ base::Bind(&OnRemoveServiceRecordError, repeating_callback)); } -template <typename... Args> -void ArcBluetoothBridge::AddAdvertisementTask( - base::OnceCallback<void(base::OnceCallback<void(Args...)>)> task, - base::OnceCallback<void(Args...)> callback) { - advertisement_task_queue_.emplace(base::BindOnce( - std::move(task), - base::BindOnce(&ArcBluetoothBridge::CompleteAdvertisementTask<Args...>, - weak_factory_.GetWeakPtr(), std::move(callback)))); - if (advertisement_task_queue_.size() != 1) - return; - // No task pending, run immediately. - std::move(advertisement_task_queue_.front()).Run(); -} - -template <typename... Args> -void ArcBluetoothBridge::CompleteAdvertisementTask( - base::OnceCallback<void(Args...)> callback, - Args... args) { - std::move(callback).Run(std::forward<Args>(args)...); - advertisement_task_queue_.pop(); // Current task is done. Pop it from queue. - if (advertisement_task_queue_.empty()) - return; - std::move(advertisement_task_queue_.front()).Run(); // Run next task. -} - bool ArcBluetoothBridge::GetAdvertisementHandle(int32_t* adv_handle) { for (int i = 0; i < kMaxAdvertisements; i++) { if (advertisements_.find(i) == advertisements_.end()) { @@ -2220,10 +2184,9 @@ void ArcBluetoothBridge::ReserveAdvertisementHandle( ReserveAdvertisementHandleCallback callback) { - AddAdvertisementTask( + advertisement_queue_.Push( base::BindOnce(&ArcBluetoothBridge::ReserveAdvertisementHandleImpl, - weak_factory_.GetWeakPtr()), - std::move(callback)); + weak_factory_.GetWeakPtr(), std::move(callback))); } void ArcBluetoothBridge::ReserveAdvertisementHandleImpl( @@ -2236,6 +2199,7 @@ LOG(WARNING) << "Out of space for advertisement data"; std::move(callback).Run(mojom::BluetoothGattStatus::GATT_FAILURE, kInvalidAdvertisementHandle); + advertisement_queue_.Pop(); return; } @@ -2245,17 +2209,16 @@ // The advertisement will be registered when we get the call // to SetAdvertisingData. For now, just return the adv_handle. std::move(callback).Run(mojom::BluetoothGattStatus::GATT_SUCCESS, adv_handle); + advertisement_queue_.Pop(); } void ArcBluetoothBridge::EnableAdvertisement( int32_t adv_handle, std::unique_ptr<device::BluetoothAdvertisement::Data> advertisement, EnableAdvertisementCallback callback) { - AddAdvertisementTask( - base::BindOnce(&ArcBluetoothBridge::EnableAdvertisementImpl, - weak_factory_.GetWeakPtr(), adv_handle, - std::move(advertisement)), - std::move(callback)); + advertisement_queue_.Push(base::BindOnce( + &ArcBluetoothBridge::EnableAdvertisementImpl, weak_factory_.GetWeakPtr(), + adv_handle, std::move(advertisement), std::move(callback))); } void ArcBluetoothBridge::EnableAdvertisementImpl( @@ -2268,7 +2231,7 @@ // updating the callee interface. auto repeating_callback = base::AdaptCallbackForRepeating(std::move(callback)); - base::Callback<void(void)> done_callback = + base::Closure done_callback = base::Bind(&ArcBluetoothBridge::OnReadyToRegisterAdvertisement, weak_factory_.GetWeakPtr(), repeating_callback, adv_handle, base::Passed(std::move(advertisement))); @@ -2278,7 +2241,8 @@ auto it = advertisements_.find(adv_handle); if (it == advertisements_.end()) { - repeating_callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); + error_callback.Run( + BluetoothAdvertisement::ErrorCode::ERROR_ADVERTISEMENT_DOES_NOT_EXIST); return; } if (it->second == nullptr) { @@ -2291,10 +2255,9 @@ void ArcBluetoothBridge::DisableAdvertisement( int32_t adv_handle, EnableAdvertisementCallback callback) { - AddAdvertisementTask( - base::BindOnce(&ArcBluetoothBridge::DisableAdvertisementImpl, - weak_factory_.GetWeakPtr(), adv_handle), - std::move(callback)); + advertisement_queue_.Push(base::BindOnce( + &ArcBluetoothBridge::DisableAdvertisementImpl, weak_factory_.GetWeakPtr(), + adv_handle, std::move(callback))); } void ArcBluetoothBridge::DisableAdvertisementImpl( @@ -2306,7 +2269,7 @@ // updating the callee interface. auto repeating_callback = base::AdaptCallbackForRepeating(std::move(callback)); - base::Callback<void(void)> done_callback = + base::Closure done_callback = base::Bind(&ArcBluetoothBridge::OnUnregisterAdvertisementDone, weak_factory_.GetWeakPtr(), repeating_callback, adv_handle); base::Callback<void(BluetoothAdvertisement::ErrorCode)> error_callback = @@ -2315,7 +2278,8 @@ auto it = advertisements_.find(adv_handle); if (it == advertisements_.end()) { - repeating_callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); + error_callback.Run( + BluetoothAdvertisement::ErrorCode::ERROR_ADVERTISEMENT_DOES_NOT_EXIST); return; } if (it->second == nullptr) { @@ -2328,10 +2292,9 @@ void ArcBluetoothBridge::ReleaseAdvertisementHandle( int32_t adv_handle, ReleaseAdvertisementHandleCallback callback) { - AddAdvertisementTask( - base::BindOnce(&ArcBluetoothBridge::ReleaseAdvertisementHandleImpl, - weak_factory_.GetWeakPtr(), adv_handle), - std::move(callback)); + advertisement_queue_.Push(base::BindOnce( + &ArcBluetoothBridge::ReleaseAdvertisementHandleImpl, + weak_factory_.GetWeakPtr(), adv_handle, std::move(callback))); } void ArcBluetoothBridge::ReleaseAdvertisementHandleImpl( @@ -2340,12 +2303,14 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (advertisements_.find(adv_handle) == advertisements_.end()) { std::move(callback).Run(mojom::BluetoothGattStatus::GATT_FAILURE); + advertisement_queue_.Pop(); return; } if (!advertisements_[adv_handle]) { advertisements_.erase(adv_handle); std::move(callback).Run(mojom::BluetoothGattStatus::GATT_SUCCESS); + advertisement_queue_.Pop(); return; } @@ -2384,6 +2349,7 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); advertisements_[adv_handle] = std::move(advertisement); std::move(callback).Run(mojom::BluetoothGattStatus::GATT_SUCCESS); + advertisement_queue_.Pop(); } void ArcBluetoothBridge::OnRegisterAdvertisementError( @@ -2395,6 +2361,7 @@ << ", error code = " << error_code; advertisements_[adv_handle] = nullptr; std::move(callback).Run(mojom::BluetoothGattStatus::GATT_FAILURE); + advertisement_queue_.Pop(); } void ArcBluetoothBridge::OnUnregisterAdvertisementDone( @@ -2403,6 +2370,7 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); advertisements_[adv_handle] = nullptr; std::move(callback).Run(mojom::BluetoothGattStatus::GATT_SUCCESS); + advertisement_queue_.Pop(); } void ArcBluetoothBridge::OnUnregisterAdvertisementError( @@ -2414,6 +2382,7 @@ << ", error code = " << error_code; advertisements_[adv_handle] = nullptr; std::move(callback).Run(mojom::BluetoothGattStatus::GATT_FAILURE); + advertisement_queue_.Pop(); } void ArcBluetoothBridge::OnReleaseAdvertisementHandleDone( @@ -2422,6 +2391,7 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); advertisements_.erase(adv_handle); std::move(callback).Run(mojom::BluetoothGattStatus::GATT_SUCCESS); + advertisement_queue_.Pop(); } void ArcBluetoothBridge::OnReleaseAdvertisementHandleError( @@ -2433,10 +2403,12 @@ << ", error code = " << error_code; advertisements_.erase(adv_handle); std::move(callback).Run(mojom::BluetoothGattStatus::GATT_FAILURE); + advertisement_queue_.Pop(); } void ArcBluetoothBridge::OnDiscoveryError() { LOG(WARNING) << "failed to change discovery state"; + discovery_queue_.Pop(); } void ArcBluetoothBridge::OnPairing(mojom::BluetoothAddressPtr addr) const {
diff --git a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.h b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.h index 08dbb24..6efc659 100644 --- a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.h +++ b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.h
@@ -15,9 +15,9 @@ #include <vector> #include "base/callback_forward.h" -#include "base/containers/queue.h" #include "base/threading/thread_checker.h" #include "base/timer/timer.h" +#include "chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue.h" #include "components/arc/common/bluetooth.mojom.h" #include "components/arc/common/intent_helper.mojom.h" #include "components/arc/connection_observer.h" @@ -331,13 +331,6 @@ ReleaseAdvertisementHandleCallback callback) override; private: - template <typename... Args> - void AddAdvertisementTask( - base::OnceCallback<void(base::OnceCallback<void(Args...)>)> task, - base::OnceCallback<void(Args...)> callback); - template <typename... Args> - void CompleteAdvertisementTask(base::OnceCallback<void(Args...)> callback, - Args... args); void ReserveAdvertisementHandleImpl( ReserveAdvertisementHandleCallback callback); void EnableAdvertisementImpl( @@ -350,6 +343,9 @@ int32_t adv_handle, ReleaseAdvertisementHandleCallback callback); + void StartDiscoveryImpl(bool le_scan); + void CancelDiscoveryImpl(); + template <typename InstanceType, typename HostType> class ConnectionObserverImpl; @@ -362,7 +358,6 @@ void OnPoweredError(AdapterStateCallback callback) const; void OnDiscoveryStarted( std::unique_ptr<device::BluetoothDiscoverySession> session); - void OnDiscoveryStopped(); void OnDiscoveryError(); void OnPairing(mojom::BluetoothAddressPtr addr) const; void OnPairedDone(mojom::BluetoothAddressPtr addr) const; @@ -619,7 +614,8 @@ enum { kMaxAdvertisements = 1 }; std::map<int32_t, scoped_refptr<device::BluetoothAdvertisement>> advertisements_; - base::queue<base::OnceClosure> advertisement_task_queue_; + ArcBluetoothTaskQueue advertisement_queue_; + ArcBluetoothTaskQueue discovery_queue_; THREAD_CHECKER(thread_checker_);
diff --git a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue.cc b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue.cc new file mode 100644 index 0000000..c897484 --- /dev/null +++ b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue.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 <utility> + +#include "chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue.h" + +namespace arc { + +ArcBluetoothTaskQueue::ArcBluetoothTaskQueue() = default; +ArcBluetoothTaskQueue::~ArcBluetoothTaskQueue() = default; + +void ArcBluetoothTaskQueue::Push(base::OnceClosure task) { + queue_.emplace(std::move(task)); + if (queue_.size() == 1) + std::move(queue_.front()).Run(); +} + +void ArcBluetoothTaskQueue::Pop() { + queue_.pop(); + if (!queue_.empty()) + std::move(queue_.front()).Run(); +} + +} // namespace arc
diff --git a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue.h b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue.h new file mode 100644 index 0000000..ee010fae --- /dev/null +++ b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue.h
@@ -0,0 +1,32 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_ARC_BLUETOOTH_ARC_BLUETOOTH_TASK_QUEUE_H_ +#define CHROME_BROWSER_CHROMEOS_ARC_BLUETOOTH_ARC_BLUETOOTH_TASK_QUEUE_H_ + +#include "base/callback.h" +#include "base/containers/queue.h" + +namespace arc { + +// A queue to ensure serial and ordered execution of tasks. +class ArcBluetoothTaskQueue { + public: + ArcBluetoothTaskQueue(); + ~ArcBluetoothTaskQueue(); + + // Pushes |task| into this queue. + void Push(base::OnceClosure task); + + // Pops the current task from this queue, indicating its completion. + void Pop(); + + private: + base::queue<base::OnceClosure> queue_; + DISALLOW_COPY_AND_ASSIGN(ArcBluetoothTaskQueue); +}; + +} // namespace arc + +#endif // CHROME_BROWSER_CHROMEOS_ARC_BLUETOOTH_ARC_BLUETOOTH_TASK_QUEUE_H_
diff --git a/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue_unittest.cc b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue_unittest.cc new file mode 100644 index 0000000..d79fea38 --- /dev/null +++ b/chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue_unittest.cc
@@ -0,0 +1,36 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_task_queue.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace arc { + +TEST(ArcBluetoothTaskQueueTest, Serial) { + bool done = false; + ArcBluetoothTaskQueue task_queue; + task_queue.Push(base::DoNothing()); + task_queue.Push(base::BindOnce([](bool* done) { *done = true; }, &done)); + EXPECT_FALSE(done); + task_queue.Pop(); + EXPECT_TRUE(done); + task_queue.Pop(); +} + +TEST(ArcBluetoothTaskQueueTest, Order) { + std::string str; + ArcBluetoothTaskQueue task_queue; + task_queue.Push(base::BindOnce([](std::string* str) { *str += '1'; }, &str)); + task_queue.Push(base::BindOnce([](std::string* str) { *str += '2'; }, &str)); + task_queue.Push(base::BindOnce([](std::string* str) { *str += '3'; }, &str)); + task_queue.Pop(); + task_queue.Pop(); + task_queue.Pop(); + EXPECT_EQ("123", str); +} + +} // namespace arc
diff --git a/chrome/browser/chromeos/drive/drivefs_test_support.cc b/chrome/browser/chromeos/drive/drivefs_test_support.cc new file mode 100644 index 0000000..c1e154d --- /dev/null +++ b/chrome/browser/chromeos/drive/drivefs_test_support.cc
@@ -0,0 +1,72 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/drive/drivefs_test_support.h" + +#include <string> +#include <utility> + +#include "base/json/json_writer.h" +#include "base/path_service.h" +#include "base/test/bind_test_util.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_paths.h" +#include "components/drive/drive_pref_names.h" +#include "components/prefs/pref_service.h" + +namespace drive { + +const char FakeDriveFsHelper::kPredefinedProfileSalt[] = "salt"; + +FakeDriveFsHelper::FakeDriveFsHelper(Profile* profile, + const base::FilePath& mount_path) + : mount_path_(mount_path), fake_drivefs_(mount_path_) { + profile->GetPrefs()->SetString( + drive::prefs::kDriveFsProfileSalt, + drive::FakeDriveFsHelper::kPredefinedProfileSalt); + fake_drivefs_.RegisterMountingForAccountId( + base::BindLambdaForTesting([profile]() { + auto* user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile); + if (!user) + return std::string(); + + return base::MD5String(FakeDriveFsHelper::kPredefinedProfileSalt + + ("-" + user->GetAccountId().GetAccountIdKey())); + })); +} +FakeDriveFsHelper::~FakeDriveFsHelper() = default; + +base::RepeatingCallback< + std::unique_ptr<drivefs::DriveFsHost::MojoConnectionDelegate>()> +FakeDriveFsHelper::CreateFakeDriveFsConnectionDelegateFactory() { + return base::BindRepeating(&drivefs::FakeDriveFs::CreateConnectionDelegate, + base::Unretained(&fake_drivefs_)); +} + +bool SetUpUserDataDirectoryForDriveFsTest() { + auto known_users_list = std::make_unique<base::ListValue>(); + auto user_dict = std::make_unique<base::DictionaryValue>(); + user_dict->SetString("account_type", "google"); + user_dict->SetString("email", "testuser@gmail.com"); + user_dict->SetString("gaia_id", "123456"); + known_users_list->Append(std::move(user_dict)); + + base::DictionaryValue local_state; + local_state.SetList("KnownUsers", std::move(known_users_list)); + + std::string local_state_json; + if (!base::JSONWriter::Write(local_state, &local_state_json)) + return false; + + base::FilePath local_state_file; + if (!base::PathService::Get(chrome::DIR_USER_DATA, &local_state_file)) + return false; + local_state_file = local_state_file.Append(chrome::kLocalStateFilename); + return base::WriteFile(local_state_file, local_state_json.data(), + local_state_json.size()) != -1; +} + +} // namespace drive
diff --git a/chrome/browser/chromeos/drive/drivefs_test_support.h b/chrome/browser/chromeos/drive/drivefs_test_support.h new file mode 100644 index 0000000..5966b1398 --- /dev/null +++ b/chrome/browser/chromeos/drive/drivefs_test_support.h
@@ -0,0 +1,44 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_DRIVE_DRIVEFS_TEST_SUPPORT_H_ +#define CHROME_BROWSER_CHROMEOS_DRIVE_DRIVEFS_TEST_SUPPORT_H_ + +#include <memory> + +#include "base/callback_forward.h" +#include "base/files/file_path.h" +#include "chromeos/components/drivefs/drivefs_host.h" +#include "chromeos/components/drivefs/fake_drivefs.h" + +class Profile; + +namespace drive { + +bool SetUpUserDataDirectoryForDriveFsTest(); + +class FakeDriveFsHelper { + public: + static const char kPredefinedProfileSalt[]; + + FakeDriveFsHelper(Profile* profile, const base::FilePath& mount_path); + ~FakeDriveFsHelper(); + + base::RepeatingCallback< + std::unique_ptr<drivefs::DriveFsHost::MojoConnectionDelegate>()> + CreateFakeDriveFsConnectionDelegateFactory(); + + const base::FilePath& mount_path() { return mount_path_; } + drivefs::FakeDriveFs& fake_drivefs() { return fake_drivefs_; } + + private: + const base::FilePath mount_path_; + drivefs::FakeDriveFs fake_drivefs_; + + DISALLOW_COPY_AND_ASSIGN(FakeDriveFsHelper); +}; + +} // namespace drive + +#endif // CHROME_BROWSER_CHROMEOS_DRIVE_DRIVEFS_TEST_SUPPORT_H_
diff --git a/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc b/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc index 41045f4..3dc5a951 100644 --- a/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc +++ b/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc
@@ -11,6 +11,7 @@ #include "base/path_service.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/drive/drive_integration_service.h" +#include "chrome/browser/chromeos/drive/drivefs_test_support.h" #include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/file_manager/mount_test_util.h" #include "chrome/browser/chromeos/file_manager/volume_manager.h" @@ -23,6 +24,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" +#include "chromeos/chromeos_features.h" #include "chromeos/chromeos_switches.h" #include "components/drive/service/fake_drive_service.h" #include "components/session_manager/core/session_manager.h" @@ -86,8 +88,10 @@ class FakeSelectFileDialog : public ui::SelectFileDialog { public: FakeSelectFileDialog(ui::SelectFileDialog::Listener* listener, - std::unique_ptr<ui::SelectFilePolicy> policy) - : ui::SelectFileDialog(listener, std::move(policy)) {} + std::unique_ptr<ui::SelectFilePolicy> policy, + const base::FilePath& drivefs_root) + : ui::SelectFileDialog(listener, std::move(policy)), + drivefs_root_(drivefs_root) {} void SelectFileImpl(Type type, const base::string16& title, @@ -97,8 +101,12 @@ const base::FilePath::StringType& default_extension, gfx::NativeWindow owning_window, void* params) override { - listener_->FileSelected(base::FilePath("/special/drive-user/root/test_dir"), - 0, nullptr); + listener_->FileSelected( + (base::FeatureList::IsEnabled(chromeos::features::kDriveFs) + ? drivefs_root_ + : base::FilePath("/special/drive-user")) + .Append("root/test_dir"), + 0, nullptr); } bool IsRunning(gfx::NativeWindow owning_window) const override { @@ -111,15 +119,23 @@ private: ~FakeSelectFileDialog() override = default; + + const base::FilePath drivefs_root_; }; class FakeSelectFileDialogFactory : public ui::SelectFileDialogFactory { + public: + explicit FakeSelectFileDialogFactory(const base::FilePath& drivefs_root) + : drivefs_root_(drivefs_root) {} + private: ui::SelectFileDialog* Create( ui::SelectFileDialog::Listener* listener, std::unique_ptr<ui::SelectFilePolicy> policy) override { - return new FakeSelectFileDialog(listener, std::move(policy)); + return new FakeSelectFileDialog(listener, std::move(policy), drivefs_root_); } + + const base::FilePath drivefs_root_; }; // Sets up the initial file system state for native local and restricted native @@ -283,6 +299,10 @@ FileSystemExtensionApiTestBase() = default; ~FileSystemExtensionApiTestBase() override = default; + bool SetUpUserDataDirectory() override { + return drive::SetUpUserDataDirectoryForDriveFsTest(); + } + void SetUp() override { InitTestFileSystem(); extensions::ExtensionApiTest::SetUp(); @@ -485,13 +505,21 @@ // could exist simultaneously. DCHECK(!fake_drive_service_); fake_drive_service_ = CreateDriveService(); + base::FilePath drivefs_mount_point; + InitializeLocalFileSystem("drive-user/root", &drivefs_root_, + &drivefs_mount_point); + fake_drivefs_helper_ = std::make_unique<drive::FakeDriveFsHelper>( + profile, drivefs_mount_point.DirName()); return new drive::DriveIntegrationService( profile, nullptr, fake_drive_service_, "", test_cache_root_.GetPath(), - nullptr); + nullptr, + fake_drivefs_helper_->CreateFakeDriveFsConnectionDelegateFactory()); } base::ScopedTempDir test_cache_root_; + base::ScopedTempDir drivefs_root_; drive::FakeDriveService* fake_drive_service_ = nullptr; + std::unique_ptr<drive::FakeDriveFsHelper> fake_drivefs_helper_; DriveIntegrationServiceFactory::FactoryCallback create_drive_integration_service_; std::unique_ptr<DriveIntegrationServiceFactory::ScopedFactoryForTest> @@ -635,10 +663,26 @@ // DriveIntegrationService factory function for this test. drive::DriveIntegrationService* CreateDriveIntegrationService( Profile* profile) { + // Ignore signin and lock screen apps profile. + if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() || + profile->GetPath() == + chromeos::ProfileHelper::GetLockScreenAppProfilePath()) { + return nullptr; + } + + // LocalAndDriveFileSystemExtensionApiTest doesn't expect that several user + // profiles could exist simultaneously. + DCHECK(!fake_drive_service_); fake_drive_service_ = CreateDriveService(); + base::FilePath drivefs_mount_point; + InitializeLocalFileSystem("drive-user/root", &drivefs_root_, + &drivefs_mount_point); + fake_drivefs_helper_ = std::make_unique<drive::FakeDriveFsHelper>( + profile, drivefs_mount_point.DirName()); return new drive::DriveIntegrationService( - profile, nullptr, fake_drive_service_, "drive", - test_cache_root_.GetPath(), nullptr); + profile, nullptr, fake_drive_service_, "", test_cache_root_.GetPath(), + nullptr, + fake_drivefs_helper_->CreateFakeDriveFsConnectionDelegateFactory()); } private: @@ -648,7 +692,9 @@ // For drive volume. base::ScopedTempDir test_cache_root_; + base::ScopedTempDir drivefs_root_; drive::FakeDriveService* fake_drive_service_ = nullptr; + std::unique_ptr<drive::FakeDriveFsHelper> fake_drivefs_helper_; DriveIntegrationServiceFactory::FactoryCallback create_drive_integration_service_; std::unique_ptr<DriveIntegrationServiceFactory::ScopedFactoryForTest> @@ -765,7 +811,8 @@ } IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, RetainEntry) { - ui::SelectFileDialog::SetFactory(new FakeSelectFileDialogFactory()); + ui::SelectFileDialog::SetFactory(new FakeSelectFileDialogFactory( + drivefs_root_.GetPath().Append("drive-user"))); EXPECT_TRUE(RunFileSystemExtensionApiTest("file_browser/retain_entry", FILE_PATH_LITERAL("manifest.json"), "",
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc index 67f487b..cdb0c4e0 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -388,7 +388,7 @@ TestCase("openQuickView").TabletMode(), TestCase("openQuickViewImage"), TestCase("openQuickViewVideo"), -// QuickView PDF test fails on MSAN, crbug.com/768070 crbug.com/891150 +// QuickView PDF test fails on MSAN, crbug.com/768070 #if !defined(MEMORY_SANITIZER) TestCase("openQuickViewPdf"), #endif @@ -398,6 +398,7 @@ TestCase("openQuickViewBackgroundColorHtml"), TestCase("openQuickViewDrive"), TestCase("openQuickViewDrive").EnableDriveFs(), + TestCase("openQuickViewCrostini"), TestCase("openQuickViewUsb"), TestCase("openQuickViewMtp"), TestCase("closeQuickView")));
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc index 943699e..e068abd8 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -25,6 +25,7 @@ #include "chrome/browser/chromeos/crostini/crostini_manager.h" #include "chrome/browser/chromeos/crostini/crostini_pref_names.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" +#include "chrome/browser/chromeos/drive/drivefs_test_support.h" #include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/file_manager/app_id.h" #include "chrome/browser/chromeos/file_manager/file_manager_test_util.h" @@ -35,9 +36,7 @@ #include "chrome/browser/notifications/notification_display_service_tester.h" #include "chrome/browser/sync_file_system/mock_remote_file_sync_service.h" #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h" -#include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_features.h" -#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/api/file_manager_private.h" #include "chromeos/chromeos_features.h" @@ -48,7 +47,6 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/fake_cros_disks_client.h" #include "components/drive/chromeos/file_system_interface.h" -#include "components/drive/drive_pref_names.h" #include "components/drive/service/fake_drive_service.h" #include "components/prefs/pref_service.h" #include "content/public/browser/browser_thread.h" @@ -423,8 +421,6 @@ DISALLOW_COPY_AND_ASSIGN(OfflineGetDriveConnectionState); }; -constexpr char kPredefinedProfileSalt[] = "salt"; - } // anonymous namespace // LocalTestVolume: test volume for a local drive. @@ -854,7 +850,7 @@ const base::FilePath target_path = GetTargetPathForTestEntry(entry); entries_.insert(std::make_pair(target_path, entry)); - fake_drivefs_->SetMetadata( + fake_drivefs_helper_->fake_drivefs().SetMetadata( GetRelativeDrivePathForTestEntry(entry), entry.mime_type, base::FilePath(entry.target_path).BaseName().value(), entry.pinned, entry.shared_option == AddEntriesMessage::SharedOption::SHARED || @@ -897,25 +893,12 @@ CHECK(base::CreateDirectory(GetMyDrivePath())); CHECK(base::CreateDirectory(GetTeamDriveGrandRoot())); - InitializeFakeDriveFs(); - return base::BindRepeating(&drivefs::FakeDriveFs::CreateConnectionDelegate, - base::Unretained(fake_drivefs_.get())); - } + if (!fake_drivefs_helper_) { + fake_drivefs_helper_ = + std::make_unique<drive::FakeDriveFsHelper>(profile_, mount_path()); + } - void InitializeFakeDriveFs() { - fake_drivefs_ = std::make_unique<drivefs::FakeDriveFs>(mount_path()); - fake_drivefs_->RegisterMountingForAccountId(base::BindRepeating( - [](Profile* profile) { - auto* user = - chromeos::ProfileHelper::Get()->GetUserByProfile(profile); - if (!user) - return std::string(); - - return base::MD5String( - kPredefinedProfileSalt + - ("-" + user->GetAccountId().GetAccountIdKey())); - }, - profile_)); + return fake_drivefs_helper_->CreateFakeDriveFsConnectionDelegateFactory(); } // Updates the ModifiedTime of the entry, and its parent directories if @@ -988,7 +971,7 @@ Profile* const profile_; std::map<base::FilePath, const AddEntriesMessage::TestEntryInfo> entries_; - std::unique_ptr<drivefs::FakeDriveFs> fake_drivefs_; + std::unique_ptr<drive::FakeDriveFsHelper> fake_drivefs_helper_; DISALLOW_COPY_AND_ASSIGN(DriveFsTestVolume); }; @@ -1037,6 +1020,7 @@ } std::vector<base::Feature> enabled_features; + std::vector<base::Feature> disabled_features; if (!IsGuestModeTest()) { enabled_features.emplace_back(features::kCrostini); enabled_features.emplace_back(features::kExperimentalCrostiniUI); @@ -1044,8 +1028,10 @@ } if (IsDriveFsTest()) { enabled_features.emplace_back(chromeos::features::kDriveFs); + } else { + disabled_features.emplace_back(chromeos::features::kDriveFs); } - feature_list_.InitWithFeatures(enabled_features, {}); + feature_list_.InitWithFeatures(enabled_features, disabled_features); extensions::ExtensionApiTest::SetUpCommandLine(command_line); } @@ -1054,26 +1040,7 @@ if (IsGuestModeTest()) return true; - auto known_users_list = std::make_unique<base::ListValue>(); - auto user_dict = std::make_unique<base::DictionaryValue>(); - user_dict->SetString("account_type", "google"); - user_dict->SetString("email", "testuser@gmail.com"); - user_dict->SetString("gaia_id", "123456"); - known_users_list->Append(std::move(user_dict)); - - base::DictionaryValue local_state; - local_state.SetList("KnownUsers", std::move(known_users_list)); - - std::string local_state_json; - if (!base::JSONWriter::Write(local_state, &local_state_json)) - return false; - - base::FilePath local_state_file; - if (!base::PathService::Get(chrome::DIR_USER_DATA, &local_state_file)) - return false; - local_state_file = local_state_file.Append(chrome::kLocalStateFilename); - return base::WriteFile(local_state_file, local_state_json.data(), - local_state_json.size()) != -1; + return drive::SetUpUserDataDirectoryForDriveFsTest(); } void FileManagerBrowserTestBase::SetUpInProcessBrowserTestFixture() { @@ -1422,8 +1389,6 @@ drive::DriveIntegrationService* FileManagerBrowserTestBase::CreateDriveIntegrationService(Profile* profile) { if (base::FeatureList::IsEnabled(chromeos::features::kDriveFs)) { - profile->GetPrefs()->SetString(drive::prefs::kDriveFsProfileSalt, - kPredefinedProfileSalt); drive_volumes_[profile->GetOriginalProfile()] = std::make_unique<DriveFsTestVolume>(profile->GetOriginalProfile()); if (!IsIncognitoModeTest() &&
diff --git a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc index 0b167e7326b..9713c90 100644 --- a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
@@ -330,4 +330,9 @@ StartTest(); } +IN_PROC_BROWSER_TEST_F(GalleryBrowserTest, DeleteSingleOpenPhotoOnDownloads) { + set_test_case_name("deleteSingleOpenPhotoOnDownloads"); + StartTest(); +} + } // namespace file_manager
diff --git a/chrome/browser/chromeos/policy/device_status_collector.cc b/chrome/browser/chromeos/policy/device_status_collector.cc index 80fc32d3..33835005 100644 --- a/chrome/browser/chromeos/policy/device_status_collector.cc +++ b/chrome/browser/chromeos/policy/device_status_collector.cc
@@ -281,13 +281,7 @@ } base::Version GetPlatformVersion() { - int32_t major_version; - int32_t minor_version; - int32_t bugfix_version; - base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, - &bugfix_version); - return base::Version(base::StringPrintf("%d.%d.%d", major_version, - minor_version, bugfix_version)); + return base::Version(base::SysInfo::OperatingSystemVersion()); } // Helper routine to convert from Shill-provided signal strength (percent)
diff --git a/chrome/browser/chromeos/policy/signin_profile_apps_policy_browsertest.cc b/chrome/browser/chromeos/policy/signin_profile_apps_policy_browsertest.cc index c18c4cf..30058f0 100644 --- a/chrome/browser/chromeos/policy/signin_profile_apps_policy_browsertest.cc +++ b/chrome/browser/chromeos/policy/signin_profile_apps_policy_browsertest.cc
@@ -10,6 +10,7 @@ #include "base/location.h" #include "base/logging.h" #include "base/macros.h" +#include "base/path_service.h" #include "base/strings/string_util.h" #include "base/task/post_task.h" #include "chrome/browser/browser_process.h" @@ -18,8 +19,8 @@ #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_service.h" -#include "chrome/browser/net/url_request_mock_util.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/base/in_process_browser_test.h" #include "chromeos/chromeos_switches.h" @@ -39,7 +40,8 @@ #include "extensions/common/extension.h" #include "extensions/common/extension_set.h" #include "extensions/common/features/feature_channel.h" -#include "net/test/url_request/url_request_mock_http_job.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -54,17 +56,17 @@ // profile: const char kManualTestAppId[] = "bjaiihebfngildkcjkjckolinodhliff"; const char kManualTestAppUpdateManifestPath[] = - "extensions/signin_screen_manual_test_app/update_manifest.xml"; + "/extensions/signin_screen_manual_test_app/update_manifest.xml"; // * A trivial test app which is NOT whitelisted for running in the sign-in // profile: const char kTrivialAppId[] = "mockapnacjbcdncmpkjngjalkhphojek"; const char kTrivialAppUpdateManifestPath[] = - "extensions/trivial_platform_app/update_manifest.xml"; + "/extensions/trivial_platform_app/update_manifest.xml"; // * A trivial test extension (note that extensions cannot be whitelisted for // running in the sign-in profile): const char kTrivialExtensionId[] = "mockepjebcnmhmhcahfddgfcdgkdifnc"; const char kTrivialExtensionUpdateManifestPath[] = - "extensions/trivial_extension/update_manifest.xml"; + "/extensions/trivial_extension/update_manifest.xml"; // Observer that allows waiting for an installation failure of a specific // extension/app. @@ -172,15 +174,19 @@ } void SetUpOnMainThread() override { - EnableUrlRequestMocks(); DevicePolicyCrosBrowserTest::SetUpOnMainThread(); + + embedded_test_server()->RegisterRequestHandler( + base::BindRepeating(&SigninProfileAppsPolicyTestBase::InterceptMockHttp, + base::Unretained(this))); + ASSERT_TRUE(embedded_test_server()->Start()); } void AddExtensionForForceInstallation( const std::string& extension_id, - const base::FilePath& update_manifest_relative_path) { - const GURL update_manifest_url = net::URLRequestMockHTTPJob::GetMockUrl( - update_manifest_relative_path.MaybeAsASCII()); + const std::string& update_manifest_relative_path) { + const GURL update_manifest_url = + embedded_test_server()->GetURL(update_manifest_relative_path); const std::string policy_item_value = base::ReplaceStringPlaceholders( "$1;$2", {extension_id, update_manifest_url.spec()}, nullptr); device_policy() @@ -193,12 +199,32 @@ const version_info::Channel channel_; private: - // Enables URL request mocks for making the test data files (extensions' - // update manifests and packages) available under corresponding URLs. - static void EnableUrlRequestMocks() { - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::IO}, - base::BindOnce(&chrome_browser_net::SetUrlRequestMocksEnabled, true)); + // Replace "mock.http" with "127.0.0.1:<port>" on "update_manifest.xml" files. + // Host resolver doesn't work here because the test file doesn't know the + // correct port number. + std::unique_ptr<net::test_server::HttpResponse> InterceptMockHttp( + const net::test_server::HttpRequest& request) { + const std::string kFileNameToIntercept = "update_manifest.xml"; + if (request.GetURL().ExtractFileName() != kFileNameToIntercept) + return nullptr; + + base::FilePath test_data_dir; + base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir); + // Remove the leading '/'. + std::string relative_manifest_path = request.GetURL().path().substr(1); + std::string manifest_response; + CHECK(base::ReadFileToString(test_data_dir.Append(relative_manifest_path), + &manifest_response)); + + base::ReplaceSubstringsAfterOffset( + &manifest_response, 0, "mock.http", + embedded_test_server()->host_port_pair().ToString()); + + std::unique_ptr<net::test_server::BasicHttpResponse> response( + new net::test_server::BasicHttpResponse()); + response->set_content_type("text/xml"); + response->set_content(manifest_response); + return response; } const extensions::ScopedCurrentChannel scoped_current_channel_; @@ -226,8 +252,8 @@ extensions::TestExtensionRegistryObserver registry_observer( extensions::ExtensionRegistry::Get(GetProfile()), kManualTestAppId); - AddExtensionForForceInstallation( - kManualTestAppId, base::FilePath(kManualTestAppUpdateManifestPath)); + AddExtensionForForceInstallation(kManualTestAppId, + kManualTestAppUpdateManifestPath); registry_observer.WaitForExtensionLoaded(); EXPECT_TRUE(extensions::ExtensionRegistry::Get(GetProfile()) @@ -244,8 +270,8 @@ ExtensionInstallErrorObserver install_error_observer(GetProfile(), kTrivialAppId); - AddExtensionForForceInstallation( - kTrivialAppId, base::FilePath(kTrivialAppUpdateManifestPath)); + AddExtensionForForceInstallation(kTrivialAppId, + kTrivialAppUpdateManifestPath); switch (channel_) { case version_info::Channel::UNKNOWN: @@ -271,10 +297,8 @@ ExtensionInstallation) { ExtensionInstallErrorObserver install_error_observer(GetProfile(), kTrivialExtensionId); - - AddExtensionForForceInstallation( - kTrivialExtensionId, base::FilePath(kTrivialExtensionUpdateManifestPath)); - + AddExtensionForForceInstallation(kTrivialExtensionId, + kTrivialExtensionUpdateManifestPath); install_error_observer.Wait(); EXPECT_FALSE(extensions::ExtensionRegistry::Get(GetProfile()) ->GetInstalledExtension(kTrivialExtensionId)); @@ -315,8 +339,8 @@ // app. IN_PROC_BROWSER_TEST_F(SigninProfileAppsPolicyTest, BackgroundPage) { ExtensionBackgroundPageReadyObserver page_observer(kTrivialAppId); - AddExtensionForForceInstallation( - kTrivialAppId, base::FilePath(kTrivialAppUpdateManifestPath)); + AddExtensionForForceInstallation(kTrivialAppId, + kTrivialAppUpdateManifestPath); page_observer.Wait(); } @@ -327,10 +351,10 @@ extensions::TestExtensionRegistryObserver registry_observer2( extensions::ExtensionRegistry::Get(GetProfile()), kTrivialAppId); - AddExtensionForForceInstallation( - kManualTestAppId, base::FilePath(kManualTestAppUpdateManifestPath)); - AddExtensionForForceInstallation( - kTrivialAppId, base::FilePath(kTrivialAppUpdateManifestPath)); + AddExtensionForForceInstallation(kManualTestAppId, + kManualTestAppUpdateManifestPath); + AddExtensionForForceInstallation(kTrivialAppId, + kTrivialAppUpdateManifestPath); registry_observer1.WaitForExtensionLoaded(); registry_observer2.WaitForExtensionLoaded();
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager.cc b/chrome/browser/chromeos/printing/cups_print_job_manager.cc index 65d1444..dbb15853 100644 --- a/chrome/browser/chromeos/printing/cups_print_job_manager.cc +++ b/chrome/browser/chromeos/printing/cups_print_job_manager.cc
@@ -6,6 +6,7 @@ #include <algorithm> +#include "base/metrics/histogram_macros.h" #include "chrome/browser/chromeos/printing/cups_print_job_notification_manager.h" namespace chromeos { @@ -36,6 +37,9 @@ } void CupsPrintJobManager::NotifyJobStarted(base::WeakPtr<CupsPrintJob> job) { + DCHECK(job); + print_job_start_times_[job->GetUniqueId()] = base::TimeTicks::Now(); + for (Observer& observer : observers_) observer.OnPrintJobStarted(job); } @@ -56,6 +60,8 @@ } void CupsPrintJobManager::NotifyJobCanceled(base::WeakPtr<CupsPrintJob> job) { + RecordJobDuration(job); + for (Observer& observer : observers_) observer.OnPrintJobCancelled(job); } @@ -66,8 +72,37 @@ } void CupsPrintJobManager::NotifyJobDone(base::WeakPtr<CupsPrintJob> job) { + RecordJobDuration(job); + for (Observer& observer : observers_) observer.OnPrintJobDone(job); } +// TODO(jschettler): In some instances, Chrome doesn't receive an error state +// from the printer (crbug.com/883966). For that reason, the job duration is +// currently recorded for done and cancelled print jobs without accounting +// for the added time a job may spend in a suspended or error state. +void CupsPrintJobManager::RecordJobDuration(base::WeakPtr<CupsPrintJob> job) { + DCHECK(job); + + auto it = print_job_start_times_.find(job->GetUniqueId()); + if (it == print_job_start_times_.end()) + return; + + base::TimeDelta duration = base::TimeTicks::Now() - it->second; + switch (job->state()) { + case CupsPrintJob::State::STATE_DOCUMENT_DONE: + UMA_HISTOGRAM_LONG_TIMES_100("Printing.CUPS.JobDuration.JobDone", + duration); + break; + case CupsPrintJob::State::STATE_CANCELLED: + UMA_HISTOGRAM_LONG_TIMES_100("Printing.CUPS.JobDuration.JobCancelled", + duration); + break; + default: + break; + } + print_job_start_times_.erase(job->GetUniqueId()); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager.h b/chrome/browser/chromeos/printing/cups_print_job_manager.h index a60b797..90a1750 100644 --- a/chrome/browser/chromeos/printing/cups_print_job_manager.h +++ b/chrome/browser/chromeos/printing/cups_print_job_manager.h
@@ -5,10 +5,13 @@ #ifndef CHROME_BROWSER_CHROMEOS_PRINTING_CUPS_PRINT_JOB_MANAGER_H_ #define CHROME_BROWSER_CHROMEOS_PRINTING_CUPS_PRINT_JOB_MANAGER_H_ +#include <map> #include <memory> +#include <string> #include <vector> #include "base/observer_list.h" +#include "base/time/time.h" #include "chrome/browser/chromeos/printing/cups_print_job.h" #include "components/keyed_service/core/keyed_service.h" @@ -76,6 +79,11 @@ base::ObserverList<Observer>::Unchecked observers_; private: + void RecordJobDuration(base::WeakPtr<CupsPrintJob> job); + + // Keyed by CupsPrintJob's unique ID + std::map<std::string, base::TimeTicks> print_job_start_times_; + DISALLOW_COPY_AND_ASSIGN(CupsPrintJobManager); };
diff --git a/chrome/browser/chromeos/smb_client/smb_provider.cc b/chrome/browser/chromeos/smb_client/smb_provider.cc index 2d5ef62..6319ede 100644 --- a/chrome/browser/chromeos/smb_client/smb_provider.cc +++ b/chrome/browser/chromeos/smb_client/smb_provider.cc
@@ -25,8 +25,6 @@ false /* watchable */, true /* multiple_mounts */, extensions::SOURCE_NETWORK), - // TODO(baileyberro): Localize this string, so it shows correctly in all - // languages. See l10n_util::GetStringUTF8. name_(l10n_util::GetStringUTF8(IDS_SMB_SHARES_ADD_SERVICE_MENU_OPTION)), unmount_callback_(std::move(unmount_callback)) { icon_set_.SetIcon(IconSet::IconSize::SIZE_16x16,
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc index fecb9960..b5db0cb 100644 --- a/chrome/browser/chromeos/smb_client/smb_service.cc +++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -113,11 +113,6 @@ CallMount(options, share_path, username, password, std::move(callback)); } -void SmbService::GatherSharesInNetwork(GatherSharesResponse shares_callback) { - share_finder_->GatherSharesInNetwork(base::DoNothing(), - std::move(shares_callback)); -} - void SmbService::GatherSharesInNetwork(HostDiscoveryResponse discovery_callback, GatherSharesResponse shares_callback) { share_finder_->GatherSharesInNetwork(std::move(discovery_callback),
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h index ecad4999..4afc8dcb 100644 --- a/chrome/browser/chromeos/smb_client/smb_service.h +++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -75,7 +75,6 @@ // for each of the hosts found. |discovery_callback| is called as soon as host // discovery is complete. |shares_callback| is called once per host and will // contain the URLs to the shares found. - void GatherSharesInNetwork(GatherSharesResponse shares_callback); void GatherSharesInNetwork(HostDiscoveryResponse discovery_callback, GatherSharesResponse shares_callback);
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc index afc81fc..b0745c7d 100644 --- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc +++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h" #include "chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.h" +#include "chrome/browser/platform_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h" #include "chrome/browser/undo/bookmark_undo_service_factory.h" @@ -565,8 +566,13 @@ if (params->is_from_touch) source = ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH; - chrome::DragBookmarks( - GetProfile(), nodes, web_contents->GetNativeView(), source); + chrome::DragBookmarks(GetProfile(), + { + std::move(nodes), params->drag_node_index, + platform_util::GetViewForWindow( + web_contents->GetTopLevelNativeWindow()), + source, + }); return true; }
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc index 3825045..80d9228 100644 --- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc +++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -49,6 +49,7 @@ #include "extensions/browser/extension_registry.h" #include "extensions/browser/guest_view/web_view/web_view_guest.h" #include "extensions/browser/guest_view/web_view/web_view_permission_helper.h" +#include "extensions/browser/value_store/value_store_factory.h" #include "google_apis/gaia/gaia_urls.h" #include "printing/buildflags/buildflags.h" #include "url/gurl.h"
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc index d1753118..1f47cbf 100644 --- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc +++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/extensions/api/developer_private/extension_info_generator.h" #include <iterator> +#include <memory> #include <string> #include <utility> #include <vector> @@ -222,6 +223,53 @@ } } +// Creates and returns a SpecificSiteControls object for the given +// |granted_permissions| and |withheld_permissions|. +std::unique_ptr<developer::SpecificSiteControls> GetSpecificSiteControls( + const PermissionSet& runtime_granted_permissions, + const PermissionSet& withheld_permissions) { + auto controls = std::make_unique<developer::SpecificSiteControls>(); + constexpr bool kIncludeApiPermissions = false; + controls->has_all_hosts = + withheld_permissions.ShouldWarnAllHosts(kIncludeApiPermissions) || + runtime_granted_permissions.ShouldWarnAllHosts(kIncludeApiPermissions); + + auto get_distinct_hosts = [](const URLPatternSet& patterns) { + std::set<std::string> distinct_hosts; + for (URLPattern pattern : patterns) { + // We only allow addition/removal of full hosts (since from a + // permissions point of view, path is irrelevant). We always make the + // path wildcard when adding through this UI, but the optional + // permissions API may allow adding permissions with paths. + // TODO(devlin): Investigate, and possibly change the optional + // permissions API. + pattern.SetPath("/*"); + distinct_hosts.insert(pattern.GetAsString()); + } + return distinct_hosts; + }; + + std::set<std::string> distinct_granted = + get_distinct_hosts(runtime_granted_permissions.effective_hosts()); + std::set<std::string> distinct_withheld = + get_distinct_hosts(withheld_permissions.effective_hosts()); + controls->hosts.reserve(distinct_granted.size() + distinct_withheld.size()); + for (auto& host : distinct_granted) { + developer::SiteControl host_control; + host_control.host = std::move(host); + host_control.granted = true; + controls->hosts.push_back(std::move(host_control)); + } + for (auto& host : distinct_withheld) { + developer::SiteControl host_control; + host_control.host = std::move(host); + host_control.granted = false; + controls->hosts.push_back(std::move(host_control)); + } + + return controls; +} + // Populates the |permissions| data for the given |extension|. void AddPermissionsInfo(content::BrowserContext* browser_context, const Extension& extension, @@ -284,22 +332,9 @@ permissions->host_access = developer::HOST_ACCESS_ON_CLICK; } else { permissions->host_access = developer::HOST_ACCESS_ON_SPECIFIC_SITES; - std::set<std::string> distinct_hosts; - for (auto pattern : runtime_granted_permissions->effective_hosts()) { - // We only allow addition/removal of full hosts (since from a - // permissions point of view, path is irrelevant). We always make the - // path wildcard when adding through this UI, but the optional - // permissions API may allow adding permissions with paths. - // TODO(devlin): Investigate, and possibly change the optional - // permissions API. - pattern.SetPath("/*"); - distinct_hosts.insert(pattern.GetAsString()); - } - - permissions->runtime_host_permissions = - std::make_unique<std::vector<std::string>>( - std::make_move_iterator(distinct_hosts.begin()), - std::make_move_iterator(distinct_hosts.end())); + permissions->specific_site_controls = GetSpecificSiteControls( + *runtime_granted_permissions, + extension.permissions_data()->withheld_permissions()); } } }
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc index 07743cc3..12a9a3e 100644 --- a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc +++ b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
@@ -71,6 +71,22 @@ return nullptr; } +// Converts the SiteControls hosts list to a JSON string. This makes test +// validation considerably more concise and readable. +std::string SiteControlsToString( + const std::vector<developer::SiteControl>& controls) { + base::Value list(base::Value::Type::LIST); + list.GetList().reserve(controls.size()); + for (const auto& control : controls) { + std::unique_ptr<base::Value> control_value = control.ToValue(); + list.GetList().push_back(std::move(*control_value)); + } + + std::string json; + CHECK(base::JSONWriter::Write(list, &json)); + return json; +} + } // namespace class ExtensionInfoGeneratorUnitTest : public ExtensionServiceTestBase { @@ -296,7 +312,7 @@ ++i; } EXPECT_EQ(developer::HOST_ACCESS_NONE, info->permissions.host_access); - EXPECT_FALSE(info->permissions.runtime_host_permissions); + EXPECT_FALSE(info->permissions.specific_site_controls); ASSERT_EQ(2u, info->runtime_errors.size()); const api::developer_private::RuntimeError& runtime_error = @@ -411,7 +427,7 @@ // The extension should be set to run on all sites. EXPECT_EQ(developer::HOST_ACCESS_ON_ALL_SITES, info->permissions.host_access); - EXPECT_FALSE(info->permissions.runtime_host_permissions); + EXPECT_FALSE(info->permissions.specific_site_controls); // With runtime host permissions, no host permissions are added to // |simple_permissions|. EXPECT_THAT(info->permissions.simple_permissions, testing::IsEmpty()); @@ -423,18 +439,21 @@ permissions_modifier.SetWithholdHostPermissions(true); info = GenerateExtensionInfo(all_urls_extension->id()); EXPECT_EQ(developer::HOST_ACCESS_ON_CLICK, info->permissions.host_access); - EXPECT_FALSE(info->permissions.runtime_host_permissions); + EXPECT_FALSE(info->permissions.specific_site_controls); EXPECT_THAT(info->permissions.simple_permissions, testing::IsEmpty()); // Granting a host permission should set the extension to run on specific - // sites, and those sites should be in the runtime_host_permissions set. + // sites, and those sites should be in the specific_site_controls.hosts set. permissions_modifier.GrantHostPermission(GURL("https://example.com")); info = GenerateExtensionInfo(all_urls_extension->id()); EXPECT_EQ(developer::HOST_ACCESS_ON_SPECIFIC_SITES, info->permissions.host_access); - ASSERT_TRUE(info->permissions.runtime_host_permissions); - EXPECT_THAT(*info->permissions.runtime_host_permissions, - testing::UnorderedElementsAre("https://example.com/*")); + ASSERT_TRUE(info->permissions.specific_site_controls); + EXPECT_EQ( + R"([{"granted":true,"host":"https://example.com/*"},)" + R"({"granted":false,"host":"*://*/*"}])", + SiteControlsToString(info->permissions.specific_site_controls->hosts)); + EXPECT_TRUE(info->permissions.specific_site_controls->has_all_hosts); EXPECT_THAT(info->permissions.simple_permissions, testing::IsEmpty()); // An extension that doesn't request any host permissions should not have @@ -443,7 +462,7 @@ CreateExtension("no urls", ListBuilder().Build(), Manifest::INTERNAL); info = GenerateExtensionInfo(no_urls_extension->id()); EXPECT_EQ(developer::HOST_ACCESS_NONE, info->permissions.host_access); - EXPECT_FALSE(info->permissions.runtime_host_permissions); + EXPECT_FALSE(info->permissions.specific_site_controls); } TEST_F(ExtensionInfoGeneratorUnitTest, RuntimeHostPermissionsWithoutFeature) { @@ -455,13 +474,13 @@ std::unique_ptr<developer::ExtensionInfo> info = GenerateExtensionInfo(all_urls_extension->id()); EXPECT_EQ(developer::HOST_ACCESS_NONE, info->permissions.host_access); - EXPECT_FALSE(info->permissions.runtime_host_permissions); + EXPECT_FALSE(info->permissions.specific_site_controls); ASSERT_EQ(1u, info->permissions.simple_permissions.size()); EXPECT_EQ("Read and change all your data on the websites you visit", info->permissions.simple_permissions[0].message); } -// Tests that runtime_host_permissions is correctly populated when permissions +// Tests that specific_site_controls is correctly populated when permissions // are granted by the user beyond what the extension originally requested in the // manifest. TEST_F(ExtensionInfoGeneratorUnitTest, @@ -501,9 +520,54 @@ info = GenerateExtensionInfo(extension->id()); EXPECT_EQ(developer::HOST_ACCESS_ON_SPECIFIC_SITES, info->permissions.host_access); - ASSERT_TRUE(info->permissions.runtime_host_permissions); - EXPECT_THAT(*info->permissions.runtime_host_permissions, - testing::UnorderedElementsAre("*://chromium.org/*")); + ASSERT_TRUE(info->permissions.specific_site_controls); + EXPECT_EQ( + R"([{"granted":true,"host":"*://chromium.org/*"},)" + R"({"granted":false,"host":"http://*/*"}])", + SiteControlsToString(info->permissions.specific_site_controls->hosts)); + EXPECT_TRUE(info->permissions.specific_site_controls->has_all_hosts); +} + +// Tests that specific_site_controls is correctly populated when the extension +// requests access to specific hosts. +TEST_F(ExtensionInfoGeneratorUnitTest, RuntimeHostPermissionsSpecificHosts) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + extensions_features::kRuntimeHostPermissions); + + scoped_refptr<const Extension> extension = + CreateExtension("extension", + ListBuilder() + .Append("https://example.com/*") + .Append("https://chromium.org/*") + .Build(), + Manifest::INTERNAL); + + std::unique_ptr<developer::ExtensionInfo> info = + GenerateExtensionInfo(extension->id()); + + // Withhold permissions, and grant *://chromium.org/*. + ScriptingPermissionsModifier permissions_modifier(profile(), extension); + permissions_modifier.SetWithholdHostPermissions(true); + URLPattern all_chromium(Extension::kValidHostPermissionSchemes, + "https://chromium.org/*"); + PermissionSet all_chromium_set(APIPermissionSet(), ManifestPermissionSet(), + URLPatternSet({all_chromium}), + URLPatternSet({all_chromium})); + PermissionsUpdater(profile()).GrantRuntimePermissions(*extension, + all_chromium_set); + + // The generated info should use the entirety of the granted permission, + // which is *://chromium.org/*. + info = GenerateExtensionInfo(extension->id()); + EXPECT_EQ(developer::HOST_ACCESS_ON_SPECIFIC_SITES, + info->permissions.host_access); + ASSERT_TRUE(info->permissions.specific_site_controls); + EXPECT_EQ( + R"([{"granted":true,"host":"https://chromium.org/*"},)" + R"({"granted":false,"host":"https://example.com/*"}])", + SiteControlsToString(info->permissions.specific_site_controls->hosts)); + EXPECT_FALSE(info->permissions.specific_site_controls->has_all_hosts); } // Test that file:// access checkbox does not show up when the user can't
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc index 12967558..e8b2c1c 100644 --- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc +++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
@@ -5,6 +5,7 @@ #include <memory> #include "base/json/json_writer.h" +#include "base/path_service.h" #include "base/strings/stringprintf.h" #include "base/task/post_task.h" #include "base/values.h" @@ -14,7 +15,7 @@ #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" #include "chrome/browser/chromeos/settings/stub_install_attributes.h" #include "chrome/browser/extensions/extension_apitest.h" -#include "chrome/browser/net/url_request_mock_util.h" +#include "chrome/common/chrome_paths.h" #include "chrome/test/base/ui_test_utils.h" #include "chromeos/dbus/fake_session_manager_client.h" #include "chromeos/system/fake_statistics_provider.h" @@ -33,7 +34,8 @@ #include "extensions/browser/extension_registry.h" #include "extensions/browser/test_extension_registry_observer.h" #include "extensions/test/result_catcher.h" -#include "net/test/url_request/url_request_mock_http_job.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" namespace { @@ -41,10 +43,8 @@ constexpr char kSerialNumber[] = "serial_number"; constexpr char kAssetId[] = "asset_id"; constexpr char kAnnotatedLocation[] = "annotated_location"; -constexpr base::FilePath::CharType kTestExtensionDir[] = - FILE_PATH_LITERAL("extensions/api_test/enterprise_device_attributes"); -constexpr base::FilePath::CharType kUpdateManifestFileName[] = - FILE_PATH_LITERAL("update_manifest.xml"); +constexpr char kUpdateManifestPath[] = + "/extensions/api_test/enterprise_device_attributes/update_manifest.xml"; constexpr char kAffiliatedUserEmail[] = "user@example.com"; constexpr char kAffiliatedUserGaiaId[] = "1029384756"; @@ -98,6 +98,34 @@ set_chromeos_user_ = false; } + // Replace "mock.http" with "127.0.0.1:<port>" on "update_manifest.xml" files. + // Host resolver doesn't work here because the test file doesn't know the + // correct port number. + std::unique_ptr<net::test_server::HttpResponse> InterceptMockHttp( + const net::test_server::HttpRequest& request) { + const std::string kFileNameToIntercept = "update_manifest.xml"; + if (request.GetURL().ExtractFileName() != kFileNameToIntercept) + return nullptr; + + base::FilePath test_data_dir; + base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir); + // Remove the leading '/'. + std::string relative_manifest_path = request.GetURL().path().substr(1); + std::string manifest_response; + CHECK(base::ReadFileToString(test_data_dir.Append(relative_manifest_path), + &manifest_response)); + + base::ReplaceSubstringsAfterOffset( + &manifest_response, 0, "mock.http", + embedded_test_server()->host_port_pair().ToString()); + + std::unique_ptr<net::test_server::BasicHttpResponse> response( + new net::test_server::BasicHttpResponse()); + response->set_content_type("text/xml"); + response->set_content(manifest_response); + return response; + } + protected: // ExtensionApiTest void SetUpCommandLine(base::CommandLine* command_line) override { @@ -170,10 +198,8 @@ // Extensions that are force-installed come from an update URL, which // defaults to the webstore. Use a mock URL for this test with an update // manifest that includes the crx file of the test extension. - base::FilePath update_manifest_path = - base::FilePath(kTestExtensionDir).Append(kUpdateManifestFileName); - GURL update_manifest_url(net::URLRequestMockHTTPJob::GetMockUrl( - update_manifest_path.MaybeAsASCII())); + GURL update_manifest_url( + embedded_test_server()->GetURL(kUpdateManifestPath)); std::unique_ptr<base::ListValue> forcelist(new base::ListValue); forcelist->AppendString(base::StringPrintf( @@ -238,10 +264,12 @@ } IN_PROC_BROWSER_TEST_P(EnterpriseDeviceAttributesTest, Success) { - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::IO}, - base::BindOnce(chrome_browser_net::SetUrlRequestMocksEnabled, true)); - + // Setup |URLLoaderInterceptor|, which is required for force-installing the + // test extension through policy. + embedded_test_server()->RegisterRequestHandler( + base::BindRepeating(&EnterpriseDeviceAttributesTest::InterceptMockHttp, + base::Unretained(this))); + ASSERT_TRUE(embedded_test_server()->Start()); SetPolicy(); EXPECT_EQ(GetParam().affiliated, user_manager::UserManager::Get()
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc index 343df1e..2febb6e0 100644 --- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc +++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
@@ -8,12 +8,13 @@ #include <memory> #include "base/macros.h" +#include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/task/post_task.h" #include "chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h" #include "chrome/browser/net/nss_context.h" -#include "chrome/browser/net/url_request_mock_util.h" +#include "chrome/common/chrome_paths.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/policy_constants.h" #include "content/public/browser/browser_task_traits.h" @@ -24,7 +25,8 @@ #include "extensions/browser/extension_registry.h" #include "extensions/browser/test_extension_registry_observer.h" #include "net/cert/nss_cert_database.h" -#include "net/test/url_request/url_request_mock_http_job.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -104,10 +106,8 @@ 0xb5, 0x6f, 0xe9, 0x1b, 0x32, 0x91, 0x34, 0x38 }; -const base::FilePath::CharType kTestExtensionDir[] = - FILE_PATH_LITERAL("extensions/api_test/enterprise_platform_keys"); -const base::FilePath::CharType kUpdateManifestFileName[] = - FILE_PATH_LITERAL("update_manifest.xml"); +const char kUpdateManifestPath[] = + "/extensions/api_test/enterprise_platform_keys/update_manifest.xml"; void ImportPrivateKeyPKCS8ToSlot(const unsigned char* pkcs8_der, size_t pkcs8_der_size, @@ -166,6 +166,13 @@ switches::kEnableExperimentalWebPlatformFeatures); } + void SetUpOnMainThread() override { + embedded_test_server()->RegisterRequestHandler( + base::BindRepeating(&EnterprisePlatformKeysTest::InterceptMockHttp, + base::Unretained(this))); + PlatformKeysTestBase::SetUpOnMainThread(); + } + void DidGetCertDatabase(const base::Closure& done_callback, net::NSSCertDatabase* cert_db) { // In order to use a prepared certificate, import a private key to the @@ -180,10 +187,8 @@ // Extensions that are force-installed come from an update URL, which // defaults to the webstore. Use a mock URL for this test with an update // manifest that includes the crx file of the test extension. - base::FilePath update_manifest_path = - base::FilePath(kTestExtensionDir).Append(kUpdateManifestFileName); - GURL update_manifest_url(net::URLRequestMockHTTPJob::GetMockUrl( - update_manifest_path.MaybeAsASCII())); + GURL update_manifest_url( + embedded_test_server()->GetURL(kUpdateManifestPath)); std::unique_ptr<base::ListValue> forcelist(new base::ListValue); forcelist->AppendString(base::StringPrintf( @@ -201,6 +206,34 @@ } private: + // Replace "mock.http" with "127.0.0.1:<port>" on "update_manifest.xml" files. + // Host resolver doesn't work here because the test file doesn't know the + // correct port number. + std::unique_ptr<net::test_server::HttpResponse> InterceptMockHttp( + const net::test_server::HttpRequest& request) { + const std::string kFileNameToIntercept = "update_manifest.xml"; + if (request.GetURL().ExtractFileName() != kFileNameToIntercept) + return nullptr; + + base::FilePath test_data_dir; + base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir); + // Remove the leading '/'. + std::string relative_manifest_path = request.GetURL().path().substr(1); + std::string manifest_response; + CHECK(base::ReadFileToString(test_data_dir.Append(relative_manifest_path), + &manifest_response)); + + base::ReplaceSubstringsAfterOffset( + &manifest_response, 0, "mock.http", + embedded_test_server()->host_port_pair().ToString()); + + std::unique_ptr<net::test_server::BasicHttpResponse> response( + new net::test_server::BasicHttpResponse()); + response->set_content_type("text/xml"); + response->set_content(manifest_response); + return response; + } + void PrepareTestSystemSlotOnIO( crypto::ScopedTestSystemNSSKeySlot* system_slot) override { // Import a private key to the system slot. The Javascript part of this @@ -220,12 +253,6 @@ } IN_PROC_BROWSER_TEST_P(EnterprisePlatformKeysTest, Basic) { - // Enable the URLRequestMock, which is required for force-installing the - // test extension through policy. - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::IO}, - base::BindOnce(chrome_browser_net::SetUrlRequestMocksEnabled, true)); - { base::RunLoop loop; GetNSSCertDatabaseForProfile(
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc index d4c7f93b..86aeb8b 100644 --- a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc +++ b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
@@ -12,6 +12,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/apps/platform_apps/app_browsertest_util.h" #include "chrome/browser/chromeos/drive/drive_integration_service.h" +#include "chrome/browser/chromeos/drive/drivefs_test_support.h" #include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/file_manager/volume_manager.h" #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" @@ -19,6 +20,7 @@ #include "chrome/browser/extensions/api/file_system/consent_provider.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/common/chrome_paths.h" +#include "chromeos/chromeos_features.h" #include "components/drive/chromeos/file_system_interface.h" #include "components/drive/service/fake_drive_service.h" #include "components/user_manager/scoped_user_manager.h" @@ -117,6 +119,10 @@ public: FileSystemApiTestForDrive() {} + bool SetUpUserDataDirectory() override { + return drive::SetUpUserDataDirectoryForDriveFsTest(); + } + // Sets up fake Drive service for tests (this has to be injected before the // real DriveIntegrationService instance is created.) void SetUpInProcessBrowserTestFixture() override { @@ -138,13 +144,15 @@ void SetUpOnMainThread() override { PlatformAppBrowserTest::SetUpOnMainThread(); - std::unique_ptr<drive::ResourceEntry> entry; - drive::FileError error = drive::FILE_ERROR_FAILED; - integration_service_->file_system()->GetResourceEntry( - base::FilePath::FromUTF8Unsafe("drive/root"), // whatever - google_apis::test_util::CreateCopyResultCallback(&error, &entry)); - content::RunAllTasksUntilIdle(); - ASSERT_EQ(drive::FILE_ERROR_OK, error); + if (!base::FeatureList::IsEnabled(chromeos::features::kDriveFs)) { + std::unique_ptr<drive::ResourceEntry> entry; + drive::FileError error = drive::FILE_ERROR_FAILED; + integration_service_->file_system()->GetResourceEntry( + base::FilePath::FromUTF8Unsafe("drive/root"), // whatever + google_apis::test_util::CreateCopyResultCallback(&error, &entry)); + content::RunAllTasksUntilIdle(); + ASSERT_EQ(drive::FILE_ERROR_OK, error); + } } void TearDown() override { @@ -152,10 +160,18 @@ PlatformAppBrowserTest::TearDown(); }; + base::FilePath GetDriveMountPoint() { + if (base::FeatureList::IsEnabled(chromeos::features::kDriveFs)) { + return drivefs_mount_point_; + } else { + return drive::util::GetDriveMountPointPath(browser()->profile()); + } + } + private: drive::DriveIntegrationService* CreateDriveIntegrationService( Profile* profile) { - // Ignore signin profile. + // Ignore signin and lock screen apps profile. if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() || profile->GetPath() == chromeos::ProfileHelper::GetLockScreenAppProfilePath()) { @@ -167,15 +183,22 @@ DCHECK(!fake_drive_service_); fake_drive_service_ = new drive::FakeDriveService; + CHECK(drivefs_root_.CreateUniqueTempDir()); + drivefs_mount_point_ = drivefs_root_.GetPath().Append("drive-user"); + fake_drivefs_helper_ = std::make_unique<drive::FakeDriveFsHelper>( + profile, drivefs_mount_point_); + SetUpTestFileHierarchy(); integration_service_ = new drive::DriveIntegrationService( - profile, nullptr, fake_drive_service_, std::string(), - test_cache_root_.GetPath(), nullptr); + profile, nullptr, fake_drive_service_, "", test_cache_root_.GetPath(), + nullptr, + fake_drivefs_helper_->CreateFakeDriveFsConnectionDelegateFactory()); return integration_service_; } void SetUpTestFileHierarchy() { + CHECK(base::CreateDirectory(drivefs_mount_point_.Append("root"))); const std::string root = fake_drive_service_->GetRootResourceId(); AddTestFile("open_existing.txt", "Can you see me?", root); AddTestFile("open_existing1.txt", "Can you see me?", root); @@ -192,6 +215,11 @@ const std::string& parent_id) { fake_drive_service_->AddNewFile("text/plain", data, parent_id, title, false, base::Bind(&IgnoreDriveEntryResult)); + base::FilePath parent_path = drivefs_mount_point_.Append("root"); + if (parent_id == "subdir_resource_id") { + parent_path = parent_path.Append("subdir"); + } + CHECK(base::WriteFile(parent_path.Append(title), data.data(), data.size())); } void AddTestDirectory(const std::string& resource_id, @@ -200,10 +228,15 @@ fake_drive_service_->AddNewDirectoryWithResourceId( resource_id, parent_id, title, drive::AddNewDirectoryOptions(), base::Bind(&IgnoreDriveEntryResult)); + CHECK(base::CreateDirectory( + drivefs_mount_point_.Append("root").Append(title))); } base::ScopedTempDir test_cache_root_; + base::ScopedTempDir drivefs_root_; + base::FilePath drivefs_mount_point_; drive::FakeDriveService* fake_drive_service_ = nullptr; + std::unique_ptr<drive::FakeDriveFsHelper> fake_drivefs_helper_; drive::DriveIntegrationService* integration_service_ = nullptr; drive::DriveIntegrationServiceFactory::FactoryCallback create_drive_integration_service_; @@ -216,12 +249,30 @@ public: FileSystemApiTestForRequestFileSystem() : fake_user_manager_(nullptr) {} + bool SetUpUserDataDirectory() override { + return drive::SetUpUserDataDirectoryForDriveFsTest(); + } + void SetUpCommandLine(base::CommandLine* command_line) override { PlatformAppBrowserTest::SetUpCommandLine(command_line); command_line->AppendSwitchASCII( extensions::switches::kWhitelistedExtensionID, kTestingExtensionId); } + // Sets up fake Drive service for tests (this has to be injected before the + // real DriveIntegrationService instance is created.) + void SetUpInProcessBrowserTestFixture() override { + PlatformAppBrowserTest::SetUpInProcessBrowserTestFixture(); + extensions::ComponentLoader::EnableBackgroundExtensionsForTesting(); + + create_drive_integration_service_ = base::BindRepeating( + &FileSystemApiTestForRequestFileSystem::CreateDriveIntegrationService, + base::Unretained(this)); + service_factory_for_test_.reset( + new drive::DriveIntegrationServiceFactory::ScopedFactoryForTest( + &create_drive_integration_service_)); + } + void SetUpOnMainThread() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); CreateTestingFileSystem(kWritableMountPointName, @@ -289,12 +340,38 @@ fake_user_manager_->AddKioskAppUser(kiosk_app_account_id); fake_user_manager_->LoginUser(kiosk_app_account_id); } + + private: + drive::DriveIntegrationService* CreateDriveIntegrationService( + Profile* profile) { + // Ignore signin and lock screen apps profile. + if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() || + profile->GetPath() == + chromeos::ProfileHelper::GetLockScreenAppProfilePath()) { + return nullptr; + } + + CHECK(drivefs_root_.CreateUniqueTempDir()); + fake_drivefs_helper_ = std::make_unique<drive::FakeDriveFsHelper>( + profile, drivefs_root_.GetPath().Append("drive-user")); + + return new drive::DriveIntegrationService( + profile, nullptr, nullptr, "", {}, nullptr, + fake_drivefs_helper_->CreateFakeDriveFsConnectionDelegateFactory()); + } + + base::ScopedTempDir drivefs_root_; + std::unique_ptr<drive::FakeDriveFsHelper> fake_drivefs_helper_; + drive::DriveIntegrationServiceFactory::FactoryCallback + create_drive_integration_service_; + std::unique_ptr<drive::DriveIntegrationServiceFactory::ScopedFactoryForTest> + service_factory_for_test_; }; IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiOpenExistingFileTest) { - base::FilePath test_file = drive::util::GetDriveMountPointPath( - browser()->profile()).AppendASCII("root/open_existing.txt"); + base::FilePath test_file = + GetDriveMountPoint().AppendASCII("root/open_existing.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_existing")) @@ -303,8 +380,8 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiOpenExistingFileWithWriteTest) { - base::FilePath test_file = drive::util::GetDriveMountPointPath( - browser()->profile()).AppendASCII("root/open_existing.txt"); + base::FilePath test_file = + GetDriveMountPoint().AppendASCII("root/open_existing.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); ASSERT_TRUE(RunPlatformAppTest( @@ -313,8 +390,8 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiOpenMultipleSuggested) { - base::FilePath test_file = drive::util::GetDriveMountPointPath( - browser()->profile()).AppendASCII("root/open_existing.txt"); + base::FilePath test_file = + GetDriveMountPoint().AppendASCII("root/open_existing.txt"); ASSERT_TRUE(base::PathService::OverrideAndCreateIfNeeded( chrome::DIR_USER_DOCUMENTS, test_file.DirName(), true, false)); FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest(); @@ -325,10 +402,10 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiOpenMultipleExistingFilesTest) { - base::FilePath test_file1 = drive::util::GetDriveMountPointPath( - browser()->profile()).AppendASCII("root/open_existing1.txt"); - base::FilePath test_file2 = drive::util::GetDriveMountPointPath( - browser()->profile()).AppendASCII("root/open_existing2.txt"); + base::FilePath test_file1 = + GetDriveMountPoint().AppendASCII("root/open_existing1.txt"); + base::FilePath test_file2 = + GetDriveMountPoint().AppendASCII("root/open_existing2.txt"); std::vector<base::FilePath> test_files; test_files.push_back(test_file1); test_files.push_back(test_file2); @@ -341,8 +418,7 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiOpenDirectoryTest) { base::FilePath test_directory = - drive::util::GetDriveMountPointPath(browser()->profile()).AppendASCII( - "root/subdir"); + GetDriveMountPoint().AppendASCII("root/subdir"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_directory); ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_directory")) @@ -360,8 +436,7 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, MAYBE_FileSystemApiOpenDirectoryWithWriteTest) { base::FilePath test_directory = - drive::util::GetDriveMountPointPath(browser()->profile()).AppendASCII( - "root/subdir"); + GetDriveMountPoint().AppendASCII("root/subdir"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_directory); ASSERT_TRUE( @@ -372,8 +447,7 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiOpenDirectoryWithoutPermissionTest) { base::FilePath test_directory = - drive::util::GetDriveMountPointPath(browser()->profile()).AppendASCII( - "root/subdir"); + GetDriveMountPoint().AppendASCII("root/subdir"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_directory); ASSERT_TRUE(RunPlatformAppTest( @@ -384,8 +458,7 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiOpenDirectoryWithOnlyWritePermissionTest) { base::FilePath test_directory = - drive::util::GetDriveMountPointPath(browser()->profile()).AppendASCII( - "root/subdir"); + GetDriveMountPoint().AppendASCII("root/subdir"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_directory); ASSERT_TRUE(RunPlatformAppTest( @@ -395,8 +468,8 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiSaveNewFileTest) { - base::FilePath test_file = drive::util::GetDriveMountPointPath( - browser()->profile()).AppendASCII("root/save_new.txt"); + base::FilePath test_file = + GetDriveMountPoint().AppendASCII("root/save_new.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/save_new")) @@ -405,8 +478,8 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiSaveExistingFileTest) { - base::FilePath test_file = drive::util::GetDriveMountPointPath( - browser()->profile()).AppendASCII("root/save_existing.txt"); + base::FilePath test_file = + GetDriveMountPoint().AppendASCII("root/save_existing.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/save_existing")) @@ -415,8 +488,8 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiSaveNewFileWithWriteTest) { - base::FilePath test_file = drive::util::GetDriveMountPointPath( - browser()->profile()).AppendASCII("root/save_new.txt"); + base::FilePath test_file = + GetDriveMountPoint().AppendASCII("root/save_new.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/save_new_with_write")) @@ -425,8 +498,8 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive, FileSystemApiSaveExistingFileWithWriteTest) { - base::FilePath test_file = drive::util::GetDriveMountPointPath( - browser()->profile()).AppendASCII("root/save_existing.txt"); + base::FilePath test_file = + GetDriveMountPoint().AppendASCII("root/save_existing.txt"); FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( &test_file); ASSERT_TRUE(RunPlatformAppTest(
diff --git a/chrome/browser/extensions/api/storage/managed_value_store_cache.cc b/chrome/browser/extensions/api/storage/managed_value_store_cache.cc index 420ffe2..ba3dfb2c 100644 --- a/chrome/browser/extensions/api/storage/managed_value_store_cache.cc +++ b/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
@@ -235,15 +235,15 @@ ManagedValueStoreCache::ManagedValueStoreCache( BrowserContext* context, - const scoped_refptr<ValueStoreFactory>& factory, - const scoped_refptr<SettingsObserverList>& observers) + scoped_refptr<ValueStoreFactory> factory, + scoped_refptr<SettingsObserverList> observers) : profile_(Profile::FromBrowserContext(context)), policy_domain_(GetPolicyDomain(profile_)), policy_service_( policy::ProfilePolicyConnectorFactory::GetForBrowserContext(context) ->policy_service()), - storage_factory_(factory), - observers_(observers) { + storage_factory_(std::move(factory)), + observers_(std::move(observers)) { DCHECK_CURRENTLY_ON(BrowserThread::UI); policy_service_->AddObserver(policy_domain_, this);
diff --git a/chrome/browser/extensions/api/storage/managed_value_store_cache.h b/chrome/browser/extensions/api/storage/managed_value_store_cache.h index ef4c7b32..954b34b 100644 --- a/chrome/browser/extensions/api/storage/managed_value_store_cache.h +++ b/chrome/browser/extensions/api/storage/managed_value_store_cache.h
@@ -44,8 +44,8 @@ // |observers| is the list of SettingsObservers to notify when a ValueStore // changes. ManagedValueStoreCache(content::BrowserContext* context, - const scoped_refptr<ValueStoreFactory>& factory, - const scoped_refptr<SettingsObserverList>& observers); + scoped_refptr<ValueStoreFactory> factory, + scoped_refptr<SettingsObserverList> observers); ~ManagedValueStoreCache() override; private:
diff --git a/chrome/browser/extensions/api/storage/policy_value_store.cc b/chrome/browser/extensions/api/storage/policy_value_store.cc index a431343..51b4e2f 100644 --- a/chrome/browser/extensions/api/storage/policy_value_store.cc +++ b/chrome/browser/extensions/api/storage/policy_value_store.cc
@@ -27,10 +27,10 @@ PolicyValueStore::PolicyValueStore( const std::string& extension_id, - const scoped_refptr<SettingsObserverList>& observers, + scoped_refptr<SettingsObserverList> observers, std::unique_ptr<ValueStore> delegate) : extension_id_(extension_id), - observers_(observers), + observers_(std::move(observers)), delegate_(std::move(delegate)) {} PolicyValueStore::~PolicyValueStore() {}
diff --git a/chrome/browser/extensions/api/storage/policy_value_store.h b/chrome/browser/extensions/api/storage/policy_value_store.h index 69e22a47..da8da845e5 100644 --- a/chrome/browser/extensions/api/storage/policy_value_store.h +++ b/chrome/browser/extensions/api/storage/policy_value_store.h
@@ -31,7 +31,7 @@ class PolicyValueStore : public ValueStore { public: PolicyValueStore(const std::string& extension_id, - const scoped_refptr<SettingsObserverList>& observers, + scoped_refptr<SettingsObserverList> observers, std::unique_ptr<ValueStore> delegate); ~PolicyValueStore() override;
diff --git a/chrome/browser/extensions/api/storage/sync_storage_backend.cc b/chrome/browser/extensions/api/storage/sync_storage_backend.cc index 477b091e..57c384a5 100644 --- a/chrome/browser/extensions/api/storage/sync_storage_backend.cc +++ b/chrome/browser/extensions/api/storage/sync_storage_backend.cc
@@ -48,14 +48,14 @@ } // namespace SyncStorageBackend::SyncStorageBackend( - const scoped_refptr<ValueStoreFactory>& storage_factory, + scoped_refptr<ValueStoreFactory> storage_factory, const SettingsStorageQuotaEnforcer::Limits& quota, - const scoped_refptr<SettingsObserverList>& observers, + scoped_refptr<SettingsObserverList> observers, syncer::ModelType sync_type, const syncer::SyncableService::StartSyncFlare& flare) - : storage_factory_(storage_factory), + : storage_factory_(std::move(storage_factory)), quota_(quota), - observers_(observers), + observers_(std::move(observers)), sync_type_(sync_type), flare_(flare) { DCHECK(IsOnBackendSequence());
diff --git a/chrome/browser/extensions/api/storage/sync_storage_backend.h b/chrome/browser/extensions/api/storage/sync_storage_backend.h index 6eeaadb..5147da38 100644 --- a/chrome/browser/extensions/api/storage/sync_storage_backend.h +++ b/chrome/browser/extensions/api/storage/sync_storage_backend.h
@@ -36,9 +36,9 @@ public: // |storage_factory| is use to create leveldb storage areas. // |observers| is the list of observers to settings changes. - SyncStorageBackend(const scoped_refptr<ValueStoreFactory>& storage_factory, + SyncStorageBackend(scoped_refptr<ValueStoreFactory> storage_factory, const SettingsStorageQuotaEnforcer::Limits& quota, - const scoped_refptr<SettingsObserverList>& observers, + scoped_refptr<SettingsObserverList> observers, syncer::ModelType sync_type, const syncer::SyncableService::StartSyncFlare& flare);
diff --git a/chrome/browser/extensions/api/storage/sync_value_store_cache.cc b/chrome/browser/extensions/api/storage/sync_value_store_cache.cc index e3c5d31..a02cad4 100644 --- a/chrome/browser/extensions/api/storage/sync_value_store_cache.cc +++ b/chrome/browser/extensions/api/storage/sync_value_store_cache.cc
@@ -6,6 +6,8 @@ #include <stddef.h> +#include <utility> + #include "chrome/browser/extensions/api/storage/sync_storage_backend.h" #include "chrome/browser/sync/glue/sync_start_util.h" #include "content/public/browser/browser_thread.h" @@ -33,8 +35,8 @@ } // namespace SyncValueStoreCache::SyncValueStoreCache( - const scoped_refptr<ValueStoreFactory>& factory, - const scoped_refptr<SettingsObserverList>& observers, + scoped_refptr<ValueStoreFactory> factory, + scoped_refptr<SettingsObserverList> observers, const base::FilePath& profile_path) : initialized_(false) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -43,9 +45,9 @@ // same message loop, and any potential post of a deletion task must come // after the constructor returns. GetBackendTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(&SyncValueStoreCache::InitOnBackend, - base::Unretained(this), factory, observers, profile_path)); + FROM_HERE, base::BindOnce(&SyncValueStoreCache::InitOnBackend, + base::Unretained(this), std::move(factory), + std::move(observers), profile_path)); } SyncValueStoreCache::~SyncValueStoreCache() { @@ -85,23 +87,18 @@ } void SyncValueStoreCache::InitOnBackend( - const scoped_refptr<ValueStoreFactory>& factory, - const scoped_refptr<SettingsObserverList>& observers, + scoped_refptr<ValueStoreFactory> factory, + scoped_refptr<SettingsObserverList> observers, const base::FilePath& profile_path) { DCHECK(IsOnBackendSequence()); DCHECK(!initialized_); - app_backend_.reset(new SyncStorageBackend( - factory, - GetSyncQuotaLimits(), - observers, - syncer::APP_SETTINGS, - sync_start_util::GetFlareForSyncableService(profile_path))); - extension_backend_.reset(new SyncStorageBackend( - factory, - GetSyncQuotaLimits(), - observers, + app_backend_ = std::make_unique<SyncStorageBackend>( + factory, GetSyncQuotaLimits(), observers, syncer::APP_SETTINGS, + sync_start_util::GetFlareForSyncableService(profile_path)); + extension_backend_ = std::make_unique<SyncStorageBackend>( + std::move(factory), GetSyncQuotaLimits(), std::move(observers), syncer::EXTENSION_SETTINGS, - sync_start_util::GetFlareForSyncableService(profile_path))); + sync_start_util::GetFlareForSyncableService(profile_path)); initialized_ = true; }
diff --git a/chrome/browser/extensions/api/storage/sync_value_store_cache.h b/chrome/browser/extensions/api/storage/sync_value_store_cache.h index fb0543b..ac65c995 100644 --- a/chrome/browser/extensions/api/storage/sync_value_store_cache.h +++ b/chrome/browser/extensions/api/storage/sync_value_store_cache.h
@@ -31,8 +31,8 @@ // another for extensions. Each backend takes care of persistence and syncing. class SyncValueStoreCache : public ValueStoreCache { public: - SyncValueStoreCache(const scoped_refptr<ValueStoreFactory>& factory, - const scoped_refptr<SettingsObserverList>& observers, + SyncValueStoreCache(scoped_refptr<ValueStoreFactory> factory, + scoped_refptr<SettingsObserverList> observers, const base::FilePath& profile_path); ~SyncValueStoreCache() override; @@ -45,8 +45,8 @@ void DeleteStorageSoon(const std::string& extension_id) override; private: - void InitOnBackend(const scoped_refptr<ValueStoreFactory>& factory, - const scoped_refptr<SettingsObserverList>& observers, + void InitOnBackend(scoped_refptr<ValueStoreFactory> factory, + scoped_refptr<SettingsObserverList> observers, const base::FilePath& profile_path); bool initialized_;
diff --git a/chrome/browser/extensions/api/storage/syncable_settings_storage.cc b/chrome/browser/extensions/api/storage/syncable_settings_storage.cc index 3778715..7088ea82 100644 --- a/chrome/browser/extensions/api/storage/syncable_settings_storage.cc +++ b/chrome/browser/extensions/api/storage/syncable_settings_storage.cc
@@ -17,13 +17,12 @@ namespace extensions { SyncableSettingsStorage::SyncableSettingsStorage( - const scoped_refptr<base::ObserverListThreadSafe<SettingsObserver>>& - observers, + scoped_refptr<base::ObserverListThreadSafe<SettingsObserver>> observers, const std::string& extension_id, ValueStore* delegate, syncer::ModelType sync_type, const syncer::SyncableService::StartSyncFlare& flare) - : observers_(observers), + : observers_(std::move(observers)), extension_id_(extension_id), delegate_(delegate), sync_type_(sync_type),
diff --git a/chrome/browser/extensions/api/storage/syncable_settings_storage.h b/chrome/browser/extensions/api/storage/syncable_settings_storage.h index f382dd1..a94680ab 100644 --- a/chrome/browser/extensions/api/storage/syncable_settings_storage.h +++ b/chrome/browser/extensions/api/storage/syncable_settings_storage.h
@@ -29,13 +29,12 @@ // Decorates a ValueStore with sync behaviour. class SyncableSettingsStorage : public ValueStore { public: - SyncableSettingsStorage( - const scoped_refptr<SettingsObserverList>& observers, - const std::string& extension_id, - // Ownership taken. - ValueStore* delegate, - syncer::ModelType sync_type, - const syncer::SyncableService::StartSyncFlare& flare); + SyncableSettingsStorage(scoped_refptr<SettingsObserverList> observers, + const std::string& extension_id, + // Ownership taken. + ValueStore* delegate, + syncer::ModelType sync_type, + const syncer::SyncableService::StartSyncFlare& flare); ~SyncableSettingsStorage() override;
diff --git a/chrome/browser/extensions/component_extensions_whitelist/OWNERS b/chrome/browser/extensions/component_extensions_whitelist/OWNERS index 297afad..0f3791b57 100644 --- a/chrome/browser/extensions/component_extensions_whitelist/OWNERS +++ b/chrome/browser/extensions/component_extensions_whitelist/OWNERS
@@ -1,8 +1,8 @@ -# Adding new component extensions requires approval from -# chrome-eng-review@google.com. See comment in whitelist.h +# Adding new component extensions requires approval from the Extensions Tech +# Lead. See comment in whitelist.h set noparent -file://ENG_REVIEW_OWNERS +rdevlin.cronin@chromium.org # TEAM: extensions-dev@chromium.org # COMPONENT: Platform>Extensions
diff --git a/chrome/browser/extensions/component_extensions_whitelist/whitelist.h b/chrome/browser/extensions/component_extensions_whitelist/whitelist.h index f39be914..fd87c57 100644 --- a/chrome/browser/extensions/component_extensions_whitelist/whitelist.h +++ b/chrome/browser/extensions/component_extensions_whitelist/whitelist.h
@@ -11,7 +11,8 @@ // ============================================================================= // -// ADDING NEW EXTENSIONS REQUIRES APPROVAL from chrome-eng-review@google.com +// ADDING NEW EXTENSIONS REQUIRES APPROVAL from Extensions Tech Lead: +// rdevlin.cronin@chromium.org // // The main acceptable use of extensions in the default Chrome experience (i.e. // not installed explicitly by the user) are to implement things like the
diff --git a/chrome/browser/extensions/convert_web_app.cc b/chrome/browser/extensions/convert_web_app.cc index 95080f7..ce49f80 100644 --- a/chrome/browser/extensions/convert_web_app.cc +++ b/chrome/browser/extensions/convert_web_app.cc
@@ -142,7 +142,7 @@ // Create the manifest std::unique_ptr<base::DictionaryValue> root(new base::DictionaryValue); root->SetString(keys::kPublicKey, - web_app::GenerateExtensionKeyFromURL(web_app.app_url)); + web_app::GenerateAppKeyFromURL(web_app.app_url)); root->SetString(keys::kName, base::UTF16ToUTF8(web_app.title)); root->SetString(keys::kVersion, ConvertTimeToExtensionVersion(create_time)); root->SetString(keys::kDescription, base::UTF16ToUTF8(web_app.description));
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index ea84174..9b9d96b 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -509,6 +509,12 @@ "URLs that are in-scope of Desktop PWAs will open in a window. Requires " "#enable-desktop-pwas."; +const char kDesktopPWAsStayInWindowName[] = + "Desktop PWAs out-of-scope links open in the app window"; +const char kDesktopPWAsStayInWindowDescription[] = + "Links to sites in a different scope will open in a custom " + "tab (inside the PWA window) as opposed to in the browser."; + const char kEnableSystemWebAppsName[] = "System Web Apps"; const char kEnableSystemWebAppsDescription[] = "Experimental system for using the Desktop PWA framework for running System" @@ -558,6 +564,13 @@ "Enable showing the Previews UI in the Omnibox on Android instead of an " "InfoBar. This has no effect on other platforms."; +const char kEnableLitePageServerPreviewsName[] = "Lite Page Server Previews"; +const char kEnableLitePageServerPreviewsDescription[] = + "Enable showing Lite Page Previews served from the Chrome Data Proxy " + "service. This feature will cause Chrome to redirect eligible navigations " + "to a Google-owned domain that serves a pre-rendered version of the " + "original page."; + const char kEnableHttpFormWarningName[] = "Show in-form warnings for sensitive fields when the top-level page is not " "HTTPS";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 29b7251d..ed33e60 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -338,6 +338,9 @@ extern const char kEnableDesktopPWAsLinkCapturingName[]; extern const char kEnableDesktopPWAsLinkCapturingDescription[]; +extern const char kDesktopPWAsStayInWindowName[]; +extern const char kDesktopPWAsStayInWindowDescription[]; + extern const char kEnableSystemWebAppsName[]; extern const char kEnableSystemWebAppsDescription[]; @@ -365,6 +368,9 @@ extern const char kEnablePreviewsAndroidOmniboxUIName[]; extern const char kEnablePreviewsAndroidOmniboxUIDescription[]; +extern const char kEnableLitePageServerPreviewsName[]; +extern const char kEnableLitePageServerPreviewsDescription[]; + extern const char kEnableHttpFormWarningName[]; extern const char kEnableHttpFormWarningDescription[];
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc index b0f9e9fc..d26d6655 100644 --- a/chrome/browser/media/encrypted_media_browsertest.cc +++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -556,6 +556,13 @@ } IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VP9Profile2Video_WebM) { +#if BUILDFLAG(ENABLE_WIDEVINE) + // TODO(crbug.com/707128): Update Widevine CDM to support VP9 profile 1/2/3. + if (IsWidevine(CurrentKeySystem())) { + DVLOG(0) << "Skipping test - Widevine CDM does not support VP9 profile 2"; + return; + } +#endif // TODO(crbug.com/707127): Support VP9 Profile2 query and update mime type. TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.webm", kWebMVp9VideoOnly); @@ -595,6 +602,13 @@ DVLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE."; return; } +#if BUILDFLAG(ENABLE_WIDEVINE) + // TODO(crbug.com/707128): Update Widevine CDM to support VP9 profile 1/2/3. + if (IsWidevine(CurrentKeySystem())) { + DVLOG(0) << "Skipping test - Widevine CDM does not support VP9 profile 2"; + return; + } +#endif // TODO(crbug.com/707127): Support VP9 Profile2 query and update mime type. TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.mp4", kMp4Vp9VideoOnly);
diff --git a/chrome/browser/media/webrtc/webrtc_log_uploader.cc b/chrome/browser/media/webrtc/webrtc_log_uploader.cc index 3bf8c7a..f3b5ef01 100644 --- a/chrome/browser/media/webrtc/webrtc_log_uploader.cc +++ b/chrome/browser/media/webrtc/webrtc_log_uploader.cc
@@ -24,6 +24,7 @@ #include "components/webrtc_logging/common/partial_circular_buffer.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "mojo/public/cpp/bindings/interface_request.h" #include "net/base/load_flags.h" #include "net/base/mime_util.h" #include "net/http/http_status_code.h" @@ -31,6 +32,7 @@ #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" +#include "services/network/public/mojom/url_loader_factory.mojom.h" #include "third_party/zlib/zlib.h" using content::BrowserThread; @@ -327,6 +329,33 @@ NotifyUploadDone(response_code, report_id, upload_done_data); } +void WebRtcLogUploader::InitURLLoaderFactoryIfNeeded() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(!shutting_down_); + + if (!url_loader_factory_.is_bound()) + return; + + // Clone UI thread URLLoaderFactory for use on the IO thread. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce( + [](network::mojom::URLLoaderFactoryRequest loader_factory_request) { + g_browser_process->shared_url_loader_factory()->Clone( + std::move(loader_factory_request)); + }, + mojo::MakeRequest(&url_loader_factory_))); + // Need to set an error handler so that the class will monitor the state of + // the Mojo pipe. Without this, an errored out pipe would only be noticed + // after the URLLoaderFactory is used, and a request failed as a result. + url_loader_factory_.set_connection_error_handler(base::BindOnce( + &WebRtcLogUploader::OnFactoryConnectionClosed, base::Unretained(this))); +} + +void WebRtcLogUploader::OnFactoryConnectionClosed() { + url_loader_factory_.reset(); +} + void WebRtcLogUploader::SetupMultipart( std::string* post_data, const std::string& compressed_log, @@ -488,10 +517,9 @@ auto it = pending_uploads_.insert(pending_uploads_.begin(), std::move(simple_url_loader)); network::SimpleURLLoader* raw_loader = it->get(); + InitURLLoaderFactoryIfNeeded(); raw_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( - g_browser_process->system_network_context_manager() - ->GetSharedURLLoaderFactory() - .get(), + url_loader_factory_.get(), base::BindOnce(&WebRtcLogUploader::OnSimpleLoaderComplete, base::Unretained(this), std::move(it), upload_done_data)); } @@ -507,6 +535,7 @@ // Clear the pending uploads list, which will reset all URL loaders. pending_uploads_.clear(); + url_loader_factory_.reset(); shutting_down_ = true; }
diff --git a/chrome/browser/media/webrtc/webrtc_log_uploader.h b/chrome/browser/media/webrtc/webrtc_log_uploader.h index 81841b8..43453a9 100644 --- a/chrome/browser/media/webrtc/webrtc_log_uploader.h +++ b/chrome/browser/media/webrtc/webrtc_log_uploader.h
@@ -16,6 +16,7 @@ #include "base/sequenced_task_runner.h" #include "base/threading/thread_checker.h" #include "chrome/browser/media/webrtc/webrtc_logging_handler_host.h" +#include "services/network/public/mojom/url_loader_factory.mojom.h" namespace network { class SimpleURLLoader; @@ -104,6 +105,10 @@ FRIEND_TEST_ALL_PREFIXES(WebRtcLogUploaderTest, AddUploadedLogInfoToUploadListFile); + void InitURLLoaderFactoryIfNeeded(); + + void OnFactoryConnectionClosed(); + // Sets up a multipart body to be uploaded. The body is produced according // to RFC 2046. void SetupMultipart(std::string* post_data, @@ -188,6 +193,9 @@ // When shutting down, don't create new URL loaders. bool shutting_down_; + // URLLoaderFactory bound to the IO thread. + network::mojom::URLLoaderFactoryPtr url_loader_factory_; + DISALLOW_COPY_AND_ASSIGN(WebRtcLogUploader); };
diff --git a/chrome/browser/media_galleries/gallery_watch_manager_unittest.cc b/chrome/browser/media_galleries/gallery_watch_manager_unittest.cc index 5169442..d7d347ff 100644 --- a/chrome/browser/media_galleries/gallery_watch_manager_unittest.cc +++ b/chrome/browser/media_galleries/gallery_watch_manager_unittest.cc
@@ -20,13 +20,13 @@ #include "chrome/browser/media_galleries/media_galleries_preferences.h" #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h" #include "chrome/browser/media_galleries/media_galleries_test_util.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "components/storage_monitor/test_storage_monitor.h" #include "content/public/test/test_browser_thread_bundle.h" #include "extensions/browser/extension_system.h" #include "extensions/common/extension.h" -#include "extensions/common/permissions/media_galleries_permission.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_CHROMEOS) @@ -87,7 +87,7 @@ std::vector<std::string> read_permissions; read_permissions.push_back( - extensions::MediaGalleriesPermission::kReadPermission); + chrome_apps::MediaGalleriesPermission::kReadPermission); extension_ = AddMediaGalleriesApp("read", read_permissions, profile_.get()); manager_.reset(new GalleryWatchManager);
diff --git a/chrome/browser/media_galleries/media_galleries_permission_controller.cc b/chrome/browser/media_galleries/media_galleries_permission_controller.cc index 8a860a35..2bd7d4651 100644 --- a/chrome/browser/media_galleries/media_galleries_permission_controller.cc +++ b/chrome/browser/media_galleries/media_galleries_permission_controller.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/media_galleries/media_gallery_context_menu.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/chrome_select_file_policy.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" #include "chrome/grit/generated_resources.h" #include "components/storage_monitor/storage_info.h" #include "components/storage_monitor/storage_monitor.h" @@ -22,7 +23,6 @@ #include "extensions/browser/api/file_system/file_system_api.h" #include "extensions/browser/extension_prefs.h" #include "extensions/common/extension.h" -#include "extensions/common/permissions/media_galleries_permission.h" #include "extensions/common/permissions/permissions_data.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/simple_menu_model.h" @@ -125,10 +125,10 @@ } base::string16 MediaGalleriesPermissionController::GetSubtext() const { - extensions::MediaGalleriesPermission::CheckParam copy_to_param( - extensions::MediaGalleriesPermission::kCopyToPermission); - extensions::MediaGalleriesPermission::CheckParam delete_param( - extensions::MediaGalleriesPermission::kDeletePermission); + chrome_apps::MediaGalleriesPermission::CheckParam copy_to_param( + chrome_apps::MediaGalleriesPermission::kCopyToPermission); + chrome_apps::MediaGalleriesPermission::CheckParam delete_param( + chrome_apps::MediaGalleriesPermission::kDeletePermission); const extensions::PermissionsData* permission_data = extension_->permissions_data(); bool has_copy_to_permission = permission_data->CheckAPIPermissionWithParam(
diff --git a/chrome/browser/media_galleries/media_galleries_permission_controller_unittest.cc b/chrome/browser/media_galleries/media_galleries_permission_controller_unittest.cc index decf180..06c1933 100644 --- a/chrome/browser/media_galleries/media_galleries_permission_controller_unittest.cc +++ b/chrome/browser/media_galleries/media_galleries_permission_controller_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/media_galleries/media_galleries_permission_controller.h" + #include "base/bind.h" #include "base/command_line.h" #include "base/files/file_path.h" @@ -13,14 +15,13 @@ #include "build/build_config.h" #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/media_galleries/media_galleries_dialog_controller_test_util.h" -#include "chrome/browser/media_galleries/media_galleries_permission_controller.h" #include "chrome/browser/media_galleries/media_galleries_preferences.h" #include "chrome/browser/media_galleries/media_galleries_test_util.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" #include "chrome/test/base/testing_profile.h" #include "components/storage_monitor/storage_info.h" #include "components/storage_monitor/test_storage_monitor.h" #include "content/public/test/test_browser_thread_bundle.h" -#include "extensions/common/permissions/media_galleries_permission.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_CHROMEOS) @@ -71,7 +72,7 @@ std::vector<std::string> read_permissions; read_permissions.push_back( - extensions::MediaGalleriesPermission::kReadPermission); + chrome_apps::MediaGalleriesPermission::kReadPermission); extension_ = AddMediaGalleriesApp("read", read_permissions, profile_.get()); }
diff --git a/chrome/browser/media_galleries/media_galleries_preferences.cc b/chrome/browser/media_galleries/media_galleries_preferences.cc index a0bcf8d5..80f1b9c 100644 --- a/chrome/browser/media_galleries/media_galleries_preferences.cc +++ b/chrome/browser/media_galleries/media_galleries_preferences.cc
@@ -27,6 +27,7 @@ #include "chrome/browser/media_galleries/media_file_system_registry.h" #include "chrome/browser/media_galleries/media_galleries_histograms.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" @@ -42,7 +43,6 @@ #include "extensions/browser/pref_names.h" #include "extensions/common/extension_set.h" #include "extensions/common/permissions/api_permission.h" -#include "extensions/common/permissions/media_galleries_permission.h" #include "extensions/common/permissions/permissions_data.h" #include "ui/base/l10n/l10n_util.h" @@ -326,8 +326,8 @@ } bool HasAutoDetectedGalleryPermission(const extensions::Extension& extension) { - extensions::MediaGalleriesPermission::CheckParam param( - extensions::MediaGalleriesPermission::kAllAutoDetectedPermission); + chrome_apps::MediaGalleriesPermission::CheckParam param( + chrome_apps::MediaGalleriesPermission::kAllAutoDetectedPermission); return extension.permissions_data()->CheckAPIPermissionWithParam( extensions::APIPermission::kMediaGalleries, ¶m); }
diff --git a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc index 8acf0ac4..194e7e88 100644 --- a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc +++ b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
@@ -24,6 +24,7 @@ #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/media_galleries/media_file_system_registry.h" #include "chrome/browser/media_galleries/media_galleries_test_util.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" @@ -37,7 +38,6 @@ #include "extensions/browser/extension_system.h" #include "extensions/common/extension.h" #include "extensions/common/manifest_handlers/background_info.h" -#include "extensions/common/permissions/media_galleries_permission.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" @@ -137,12 +137,12 @@ std::vector<std::string> all_permissions; all_permissions.push_back( - extensions::MediaGalleriesPermission::kReadPermission); + chrome_apps::MediaGalleriesPermission::kReadPermission); all_permissions.push_back( - extensions::MediaGalleriesPermission::kAllAutoDetectedPermission); + chrome_apps::MediaGalleriesPermission::kAllAutoDetectedPermission); std::vector<std::string> read_permissions; read_permissions.push_back( - extensions::MediaGalleriesPermission::kReadPermission); + chrome_apps::MediaGalleriesPermission::kReadPermission); all_permission_extension = AddMediaGalleriesApp("all", all_permissions, profile_.get());
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_browsertest.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_browsertest.cc index 10cef1e..3865f87 100644 --- a/chrome/browser/net/spdyproxy/data_reduction_proxy_browsertest.cc +++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_browsertest.cc
@@ -3,12 +3,15 @@ // found in the LICENSE file. #include "base/strings/strcat.h" +#include "base/test/scoped_feature_list.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.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/data_reduction_proxy/core/common/data_reduction_proxy_switches.h" #include "components/data_reduction_proxy/proto/client_config.pb.h" #include "components/prefs/pref_service.h" @@ -63,6 +66,10 @@ } void SetUpOnMainThread() override { + scoped_feature_list_.InitAndEnableFeatureWithParameters( + features::kDataReductionProxyRobustConnection, + {{params::GetMissingViaBypassParamName(), "true"}, + {params::GetWarmupCallbackParamName(), "true"}}); host_resolver()->AddRule(kMockHost, "127.0.0.1"); EnableDataSaver(true); } @@ -92,6 +99,9 @@ EXPECT_TRUE(base_url.is_valid()) << base_url.possibly_invalid_spec(); return base_url.Resolve(relative_url); } + + private: + base::test::ScopedFeatureList scoped_feature_list_; }; IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest, ChromeProxyHeaderSet) {
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc index 8ebbac6..812c850 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -324,8 +324,14 @@ // Tests that when an active WebContents accurately tracks whether a video // is in Picture-in-Picture. +// Flaky failures on ChromeOS - http://crbug.com/892310 +#if defined(OS_CHROMEOS) +#define MAYBE_TabIconUpdated DISABLED_TabIconUpdated +#else +#define MAYBE_TabIconUpdated TabIconUpdated +#endif IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest, - TabIconUpdated) { + MAYBE_TabIconUpdated) { GURL test_page_url = ui_test_utils::GetTestUrl( base::FilePath(base::FilePath::kCurrentDirectory), base::FilePath(
diff --git a/chrome/browser/platform_util_mac.mm b/chrome/browser/platform_util_mac.mm index c560537..a4ad8f3 100644 --- a/chrome/browser/platform_util_mac.mm +++ b/chrome/browser/platform_util_mac.mm
@@ -17,6 +17,7 @@ #include "chrome/browser/platform_util_internal.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "ui/views/widget/widget.h" #include "url/gurl.h" namespace platform_util { @@ -97,14 +98,29 @@ } bool IsWindowActive(gfx::NativeWindow window) { + // If |window| is a doppelganger NSWindow being used to track an NSWindow that + // is being hosted in another process, then use the views::Widget interface to + // interact with it. + views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window); + if (widget) + return widget->IsActive(); + return [window isKeyWindow] || [window isMainWindow]; } void ActivateWindow(gfx::NativeWindow window) { + views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window); + if (widget) + return widget->Activate(); + [window makeKeyAndOrderFront:nil]; } bool IsVisible(gfx::NativeView view) { + views::Widget* widget = views::Widget::GetWidgetForNativeView(view); + if (widget) + return widget->IsVisible(); + // A reasonable approximation of how you'd expect this to behave. return (view && ![view isHiddenOrHasHiddenAncestor] &&
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc index 04b7edb..e9acffd8 100644 --- a/chrome/browser/previews/previews_lite_page_browsertest.cc +++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -586,6 +586,27 @@ histogram_tester.ExpectBucketCount("Previews.ServerLitePage.Triggered", false, 2); } + + { + // Verify a preview is only shown on slow networks. + base::HistogramTester histogram_tester; + g_browser_process->network_quality_tracker() + ->ReportEffectiveConnectionTypeForTesting( + net::EFFECTIVE_CONNECTION_TYPE_3G); + + ui_test_utils::NavigateToURL(browser(), HttpLitePageURL(200)); + + VerifyPreviewNotLoaded(); + histogram_tester.ExpectBucketCount( + "Previews.ServerLitePage.IneligibleReasons", + PreviewsLitePageNavigationThrottle::IneligibleReason::kNetworkNotSlow, + 1); + + // Reset ECT for future tests. + g_browser_process->network_quality_tracker() + ->ReportEffectiveConnectionTypeForTesting( + net::EFFECTIVE_CONNECTION_TYPE_2G); + } } // Previews InfoBar (which these tests trigger) does not work on Mac.
diff --git a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc index 81ee2c8..43f955c 100644 --- a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc +++ b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc
@@ -181,6 +181,13 @@ if (manager_->IsServerUnavailable()) ineligible_reasons.push_back(IneligibleReason::kServerUnavailable); + if (g_browser_process->network_quality_tracker() + ->GetEffectiveConnectionType() > + previews::params::GetECTThresholdForPreview( + previews::PreviewsType::LITE_PAGE_REDIRECT)) { + ineligible_reasons.push_back(IneligibleReason::kNetworkNotSlow); + } + // Record UMA. for (IneligibleReason reason : ineligible_reasons) { UMA_HISTOGRAM_ENUMERATION("Previews.ServerLitePage.IneligibleReasons",
diff --git a/chrome/browser/previews/previews_lite_page_navigation_throttle.h b/chrome/browser/previews/previews_lite_page_navigation_throttle.h index 7162747..df1c3c27 100644 --- a/chrome/browser/previews/previews_lite_page_navigation_throttle.h +++ b/chrome/browser/previews/previews_lite_page_navigation_throttle.h
@@ -38,7 +38,8 @@ kSubframeNavigation = 2, kServerUnavailable = 3, kInfoBarNotSeen = 4, - kMaxValue = kInfoBarNotSeen, + kNetworkNotSlow = 5, + kMaxValue = kNetworkNotSlow, }; // The response type from the previews server. This enum must
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js index d41584db..ab39fe7 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_get_more.js
@@ -52,6 +52,10 @@ * @private */ onNextTap_: function() { + if (this.buttonsDisabled) { + return; + } + this.buttonsDisabled = true; var hotword = this.$$('#toggle0').hasAttribute('checked'); var screenContext = this.$$('#toggle1').hasAttribute('checked'); var toggle2 = this.$$('#toggle2');
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_loading.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_loading.js index 5b539bc..c9e0479 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_loading.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_loading.js
@@ -60,6 +60,10 @@ * @private */ onSkipTap_: function() { + if (this.buttonsDisabled) { + return; + } + this.buttonsDisabled = true; chrome.send('login.AssistantOptInFlowScreen.flowFinished'); },
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_ready.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_ready.js index c8717359..c38ff2a 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_ready.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_ready.js
@@ -19,6 +19,10 @@ * @private */ onNextTap_: function() { + if (this.buttonsDisabled) { + return; + } + this.buttonsDisabled = true; chrome.send( 'login.AssistantOptInFlowScreen.ReadyScreen.userActed', ['next-pressed']);
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.js index 9717515..9a9aa00e 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_third_party.js
@@ -59,6 +59,10 @@ * @private */ onNextTap_: function() { + if (this.buttonsDisabled) { + return; + } + this.buttonsDisabled = true; chrome.send( 'login.AssistantOptInFlowScreen.ThirdPartyScreen.userActed', ['next-pressed']);
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js index 4349623..dd9362d 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
@@ -118,10 +118,13 @@ * @private */ onSkipTap_: function() { + if (this.buttonsDisabled) { + return; + } + this.buttonsDisabled = true; chrome.send( 'login.AssistantOptInFlowScreen.ValuePropScreen.userActed', ['skip-pressed']); - this.buttonsDisabled = true; }, /** @@ -130,10 +133,13 @@ * @private */ onNextTap_: function() { + if (this.buttonsDisabled) { + return; + } + this.buttonsDisabled = true; chrome.send( 'login.AssistantOptInFlowScreen.ValuePropScreen.userActed', ['next-pressed']); - this.buttonsDisabled = true; }, /**
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs index 4b8f1c5..635e21c 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -1764,12 +1764,7 @@ .expectSpeech('tab2') .clearPendingOutput() .call(press(82 /* R */, {ctrl: true})) - - // ChromeVox stays on the same node due to tree path recovery. - .call(() => { - assertEquals('tab2', - ChromeVoxState.instance.currentRange.start.node.name); - }) + .expectSpeech('tab2') .replay(); }); }); @@ -1789,31 +1784,3 @@ .replay(); }); }); - -TEST_F('BackgroundTest', 'ReinsertedNodeRecovery', function() { - var mockFeedback = this.createMockFeedback(); - this.runWithLoadedTree(function(root) {/* - <div> - <button id="start">start</button> - <button id="hot">hot</button> - </div> - <button id="end">end</button> - <script> - var div = document.body.firstElementChild; - var start = document.getElementById('start'); - document.getElementById('hot').addEventListener('focus', (evt) => { - var hot = evt.target; - hot.remove(); - div.insertAfter(hot, start); - }); - </script> - */}, function(root) { - mockFeedback.expectSpeech('start') - .clearPendingOutput() - .call(doCmd('nextObject')) - .call(doCmd('nextObject')) - .call(doCmd('nextObject')) - .expectSpeech('end', 'Button') - .replay(); - }); -});
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js index 9c3572ce..8ddb5612 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
@@ -103,7 +103,7 @@ /** @type {number} @private */ this.index_ = index; /** @type {RecoveryStrategy} */ - this.recovery_ = new TreePathRecoveryStrategy(node); + this.recovery_ = new AncestryRecoveryStrategy(node); }; /**
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs index a676b7f..563892f 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
@@ -229,18 +229,18 @@ .withoutHints() .withSpeechAndBraille(range, null, 'navigate'); - checkSpeechOutput('play|Button|audio|Tool bar', + checkSpeechOutput('play|Disabled|Button|audio|Tool bar', [ {value: new Output.EarconAction('BUTTON'), start: 0, end: 4}, - {value: 'name', start: 12, end: 17}, - {value: 'role', start: 18, end: 26} + {value: 'name', start: 21, end: 26}, + {value: 'role', start: 27, end: 35} ], o); checkBrailleOutput( - 'play btn audio tlbar', - [{value: new Output.NodeSpan(el), start: 0, end: 8}, - {value: new Output.NodeSpan(el.parent), start: 9, end: 20}], + 'play xx btn audio tlbar', + [{value: new Output.NodeSpan(el), start: 0, end: 11}, + {value: new Output.NodeSpan(el.parent), start: 12, end: 23}], o); // TODO(dmazzoni/dtseng): Replace with a query.
diff --git a/chrome/browser/resources/local_discovery/chevron_left-1x.png b/chrome/browser/resources/local_discovery/chevron_left-1x.png deleted file mode 100644 index 85d3117..0000000 --- a/chrome/browser/resources/local_discovery/chevron_left-1x.png +++ /dev/null Binary files differ
diff --git a/chrome/browser/resources/local_discovery/chevron_left-2x.png b/chrome/browser/resources/local_discovery/chevron_left-2x.png deleted file mode 100644 index 5dcdab95..0000000 --- a/chrome/browser/resources/local_discovery/chevron_left-2x.png +++ /dev/null Binary files differ
diff --git a/chrome/browser/resources/local_discovery/local_discovery.css b/chrome/browser/resources/local_discovery/local_discovery.css index bae41d1f..bb08c2f 100644 --- a/chrome/browser/resources/local_discovery/local_discovery.css +++ b/chrome/browser/resources/local_discovery/local_discovery.css
@@ -113,22 +113,3 @@ .dialog-contents { padding-left: 17px; } - -#back-link { - background: -webkit-image-set( - url(chevron_left-1x.png) 1x, - url(chevron_left-2x.png) 2x) - no-repeat; - margin-bottom: 25px; - margin-top: 6px; - padding-left: 23px; -} - -html[dir='rtl'] #back-link { - transform: scaleX(-1); -} - -html[dir='rtl'] #back-link span { - display: inline-block; - transform: scaleX(-1); -}
diff --git a/chrome/browser/resources/local_discovery/local_discovery.html b/chrome/browser/resources/local_discovery/local_discovery.html index 6a699ba..58cdea2 100644 --- a/chrome/browser/resources/local_discovery/local_discovery.html +++ b/chrome/browser/resources/local_discovery/local_discovery.html
@@ -75,18 +75,6 @@ </div> </div> - <div id="register-device-page-adding2" class="register-page"> - <h1>$i18n{addingDevice}</h1> - <div class="dialog-contents"> - <div>$i18n{addingDeviceConfirmCodeMessage}</div> - <h1 id="register-device-page-code"></h1> - <div class="button-list"> - <button class="register-cancel">$i18n{cancel}</button> - <button class="confirm-code">$i18n{confirmCode}</button> - </div> - </div> - </div> - <div id="register-page-error" class="register-page"> <h1>$i18n{addingError}</h1> <div class="dialog-contents"> @@ -100,9 +88,6 @@ </div> <header> - <a is="action-link" id="back-link" hidden> - <span>$i18n{backButton}</span> - </a> <h1>$i18n{devicesTitle}</h1> </header> @@ -126,9 +111,9 @@ <section id="cloud-print-connector-section"> <h2>$i18n{titleConnector}</h2> <div> - <p id="cloudPrintConnectorLabel" class="settings-row"></p> + <p id="cloudPrintConnectorLabel"></p> - <div class="settings-row"> + <div> <button id="cloudPrintConnectorSetupButton"></button> </div> </div>
diff --git a/chrome/browser/resources/local_discovery/local_discovery.js b/chrome/browser/resources/local_discovery/local_discovery.js index 0b9bc33..825f12c 100644 --- a/chrome/browser/resources/local_discovery/local_discovery.js +++ b/chrome/browser/resources/local_discovery/local_discovery.js
@@ -292,15 +292,6 @@ } /** - * Shows UI to confirm security code. - * @param {string} code The security code to confirm. - */ - function onRegistrationConfirmDeviceCode(code) { - setRegisterPage('register-device-page-adding2'); - $('register-device-page-code').textContent = code; - } - - /** * Update device unregistered device list, and update related strings to * reflect the number of devices available to register. * @param {string} name Name of the device. @@ -431,13 +422,6 @@ } /** - * Update visibility status for page. - */ - function updateVisibility() { - chrome.send('isVisible', [!document.hidden]); - } - - /** * Set the page that the register wizard is on. * @param {string} page_id ID string for page. */ @@ -494,14 +478,6 @@ } /** - * Confirms device code. - */ - function confirmCode() { - chrome.send('confirmCode'); - setRegisterPage('register-device-page-adding1'); - } - - /** * Retry loading the devices from Google Cloud Print. */ function retryLoadCloudDevices() { @@ -623,11 +599,6 @@ button.addEventListener('click', cancelRegistration); }); - [].forEach.call( - document.querySelectorAll('.confirm-code'), function(button) { - button.addEventListener('click', confirmCode); - }); - $('register-error-exit').addEventListener('click', cancelRegistration); @@ -643,16 +614,6 @@ $('register-overlay-login-button') .addEventListener('click', registerOverlayLoginButtonClicked); - if (loadTimeData.valueExists('backButtonURL')) { - $('back-link').hidden = false; - $('back-link').addEventListener('click', function() { - window.location.href = loadTimeData.getString('backButtonURL'); - }); - } - - updateVisibility(); - document.addEventListener('visibilitychange', updateVisibility, false); - focusManager = new LocalDiscoveryFocusManager(); focusManager.initialize(); @@ -665,7 +626,6 @@ onRegistrationFailed: onRegistrationFailed, onUnregisteredDeviceUpdate: onUnregisteredDeviceUpdate, onRegistrationConfirmedOnPrinter: onRegistrationConfirmedOnPrinter, - onRegistrationConfirmDeviceCode: onRegistrationConfirmDeviceCode, onCloudDeviceListAvailable: onCloudDeviceListAvailable, onCloudDeviceListUnavailable: onCloudDeviceListUnavailable, onDeviceCacheFlushed: onDeviceCacheFlushed,
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.css b/chrome/browser/resources/local_ntp/custom_links_edit.css index b2f29ae..a830fee 100644 --- a/chrome/browser/resources/local_ntp/custom_links_edit.css +++ b/chrome/browser/resources/local_ntp/custom_links_edit.css
@@ -128,6 +128,14 @@ margin-top: 24px; } +html:not([dir=rtl]) .buttons-container span + span { + margin-left: 16px; +} + +html[dir=rtl] .buttons-container span + span { + margin-right: 16px; +} + button { border: none; border-radius: 4px;
diff --git a/chrome/browser/resources/md_bookmarks/BUILD.gn b/chrome/browser/resources/md_bookmarks/BUILD.gn index a479745b..29cb87a 100644 --- a/chrome/browser/resources/md_bookmarks/BUILD.gn +++ b/chrome/browser/resources/md_bookmarks/BUILD.gn
@@ -26,7 +26,6 @@ ":constants", ":debouncer", ":dialog_focus_manager", - ":dnd_chip", ":dnd_manager", ":edit_dialog", ":folder_node", @@ -110,19 +109,10 @@ ] } -js_library("dnd_chip") { - deps = [ - ":types", - "//ui/webui/resources/js:cr", - "//ui/webui/resources/js:icon", - ] -} - js_library("dnd_manager") { deps = [ ":api_listener", ":debouncer", - ":dnd_chip", ":folder_node", ":store", ":types",
diff --git a/chrome/browser/resources/md_bookmarks/dnd_chip.html b/chrome/browser/resources/md_bookmarks/dnd_chip.html deleted file mode 100644 index 07b9dbf..0000000 --- a/chrome/browser/resources/md_bookmarks/dnd_chip.html +++ /dev/null
@@ -1,94 +0,0 @@ -<link rel="import" href="chrome://resources/html/polymer.html"> - -<link rel="import" href="chrome://resources/cr_elements/icons.html"> -<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> -<link rel="import" href="chrome://resources/html/icon.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> -<link rel="import" href="chrome://bookmarks/shared_style.html"> - -<dom-module id="bookmarks-dnd-chip"> - <template> - <style include="shared-style"> - :host { - --chip-height: 40px; - --chip-padding-x: 8px; - --chip-width: 172px; - - left: 0; - pointer-events: none; - position: absolute; - top: 0; - transform: translate(calc(var(--mouse-x) - var(--chip-width) * 0.5), - calc(var(--mouse-y) - var(--chip-height) * 0.8)); - z-index: 2; - } - - :host(:not([showing_])) { - display: none; - } - - .chip-container { - background-color: var(--interactive-color); - border-radius: calc(var(--chip-height) / 2); - box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.12), - 0 4px 10px 0 rgba(0, 0, 0, 0.24); - height: var(--chip-height); - left: 0; - padding: 0 var(--chip-padding-x); - position: absolute; - top: 0; - width: calc(var(--chip-width) - var(--chip-padding-x) * 2); - } - - #title { - color: white; - flex: 1; - font-weight: 500; - margin-inline-end: 8px; - margin-inline-start: 12px; - text-decoration: none; - } - - #icon-wrapper { - background: white; - border-radius: 12px; - color: var(--cr-secondary-text-color); - height: 24px; - position: relative; - width: 24px; - } - - .centered { - align-items: center; - display: flex; - justify-content: center; - } - - #count { - background: var(--google-red-500); - border-radius: 12px; - color: white; - font-weight: 500; - height: 24px; - min-width: 14px; - padding: 0 5px; - position: absolute; - right: -170px; - top: -10px; - } - - :host-context([dir='rtl']) #count { - left: 2px; - right: auto; - } - </style> - <div class="chip-container centered"> - <div id="icon-wrapper" class="centered"> - <div id="icon"></div> - </div> - <div id="title" class="elided-text"></div> - </div> - <div id="count" class="centered" hidden$="[[!isMultiItem_]]"></div> - </template> - <script src="chrome://bookmarks/dnd_chip.js"></script> -</dom-module>
diff --git a/chrome/browser/resources/md_bookmarks/dnd_chip.js b/chrome/browser/resources/md_bookmarks/dnd_chip.js deleted file mode 100644 index 22e3b63f..0000000 --- a/chrome/browser/resources/md_bookmarks/dnd_chip.js +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -Polymer({ - is: 'bookmarks-dnd-chip', - - properties: { - /** @private */ - showing_: { - type: Boolean, - reflectToAttribute: true, - }, - - /** @private */ - isMultiItem_: Boolean, - }, - - /** - * @param {number} x - * @param {number} y - * @param {!Array<BookmarkNode>} items - * @param {!BookmarkNode} dragItem - */ - showForItems: function(x, y, items, dragItem) { - this.style.setProperty('--mouse-x', x + 'px'); - this.style.setProperty('--mouse-y', y + 'px'); - - if (this.showing_) - return; - - const isFolder = !dragItem.url; - this.isMultiItem_ = items.length > 1; - - this.$.icon.className = isFolder ? 'folder-icon' : 'website-icon'; - this.$.icon.style.backgroundImage = - isFolder ? null : cr.icon.getFavicon(assert(dragItem.url)); - - this.$.title.textContent = dragItem.title; - this.$.count.textContent = items.length; - this.showing_ = true; - }, - - hide: function() { - this.showing_ = false; - }, -});
diff --git a/chrome/browser/resources/md_bookmarks/dnd_manager.html b/chrome/browser/resources/md_bookmarks/dnd_manager.html index 0a8b34b8..8469e5b 100644 --- a/chrome/browser/resources/md_bookmarks/dnd_manager.html +++ b/chrome/browser/resources/md_bookmarks/dnd_manager.html
@@ -1,4 +1,3 @@ <link rel="import" href="chrome://bookmarks/constants.html"> <link rel="import" href="chrome://bookmarks/debouncer.html"> -<link rel="import" href="chrome://bookmarks/dnd_chip.html"> <script src="chrome://bookmarks/dnd_manager.js"></script>
diff --git a/chrome/browser/resources/md_bookmarks/dnd_manager.js b/chrome/browser/resources/md_bookmarks/dnd_manager.js index 248472cad..0864e0c 100644 --- a/chrome/browser/resources/md_bookmarks/dnd_manager.js +++ b/chrome/browser/resources/md_bookmarks/dnd_manager.js
@@ -213,56 +213,6 @@ }; /** - * Manages auto scrolling of elements on hover during internal drags. Native - * drags do this by themselves. - * @constructor - */ - function AutoScroller() { - /** @const {number} */ - this.SCROLL_ZONE_LENGTH = 20; - /** @const {number} */ - this.SCROLL_DISTANCE = 10; - /** @const {number} */ - this.SCROLL_INTERVAL = 100; - /** @private {?number} */ - this.intervalId_ = null; - } - - AutoScroller.prototype = { - /** @param {!Event} e */ - update: function(e) { - this.reset(); - - const scrollParent = e.path.find((el) => { - return el.nodeType == Node.ELEMENT_NODE && - window.getComputedStyle(el).overflowY == 'auto'; - }); - - if (!scrollParent) - return; - - const rect = scrollParent.getBoundingClientRect(); - let yDelta = 0; - if (e.clientY < rect.top + this.SCROLL_ZONE_LENGTH) - yDelta = -this.SCROLL_DISTANCE; - else if (e.clientY > rect.bottom - this.SCROLL_ZONE_LENGTH) - yDelta = this.SCROLL_DISTANCE; - - this.intervalId_ = window.setInterval(() => { - scrollParent.scrollTop += yDelta; - }, this.SCROLL_INTERVAL); - }, - - reset: function() { - if (this.intervalId_ == null) - return; - - window.clearInterval(this.intervalId_); - this.intervalId_ = null; - }, - }; - - /** * Encapsulates the behavior of the drag and drop indicator which puts a line * between items or highlights folders which are valid drop targets. * @constructor @@ -357,22 +307,6 @@ /** * Manages drag and drop events for the bookmarks-app. * - * This class manages an internal drag and drop based on mouse events and then - * delegates to the native drag and drop in chrome.bookmarkManagerPrivate when - * the mouse leaves the web content area. This allows us to render a drag and - * drop chip UI for internal drags, while correctly handling and avoiding - * conflict with native drags. - * - * The event flows look like - * - * mousedown -> mousemove -> mouseup - * | - * v - * dragstart/dragleave (if the drag leaves the browser window) - * | - * v - * external drag -> bookmarkManagerPrivate.onDragEnter -> dragover -> drop - * * @constructor */ function DNDManager() { @@ -388,9 +322,6 @@ /** @private {Object<string, function(!Event)>} */ this.documentListeners_ = null; - /** @private {?bookmarks.AutoScroller} */ - this.autoScroller_ = null; - /** @private {?bookmarks.AutoExpander} */ this.autoExpander_ = null; @@ -399,25 +330,6 @@ * @private {!Object} */ this.timerProxy_ = window; - - /** - * The bookmark drag and drop indicator chip. - * @private {BookmarksDndChipElement} - */ - this.chip_ = null; - - /** - * The element that initiated an internal drag. Not used once native drag - * starts. - * @private {BookmarkElement} - */ - this.internalDragElement_ = null; - - /** - * Where the internal drag started. - * @private {?{x: number, y: number}} - */ - this.mouseDownPos_ = null; } DNDManager.prototype = { @@ -425,14 +337,8 @@ this.dragInfo_ = new DragInfo(); this.dropIndicator_ = new DropIndicator(); this.autoExpander_ = new AutoExpander(); - this.autoScroller_ = new AutoScroller(); this.documentListeners_ = { - 'mousedown': this.onMousedown_.bind(this), - 'mousemove': this.onMouseMove_.bind(this), - 'mouseup': this.onMouseUp_.bind(this), - 'mouseleave': this.onMouseLeave_.bind(this), - 'dragstart': this.onDragStart_.bind(this), 'dragenter': this.onDragEnter_.bind(this), 'dragover': this.onDragOver_.bind(this), @@ -448,8 +354,6 @@ this.handleChromeDragEnter_.bind(this)); chrome.bookmarkManagerPrivate.onDragLeave.addListener( this.clearDragData_.bind(this)); - chrome.bookmarkManagerPrivate.onDrop.addListener( - this.clearDragData_.bind(this)); }, destroy: function() { @@ -461,151 +365,33 @@ }, //////////////////////////////////////////////////////////////////////////// - // MouseEvent handlers: - - /** - * @private - * @param {Event} e - */ - onMousedown_: function(e) { - const dragElement = getDragElement(e.path); - if (e.button != 0 || !dragElement) - return; - - this.internalDragElement_ = dragElement; - this.mouseDownPos_ = { - x: e.clientX, - y: e.clientY, - }; - }, - - /** - * @private - * @param {Event} e - */ - onMouseMove_: function(e) { - // mousemove events still fire when dragged onto the the bookmarks bar. - // Once we are outside of the web contents, allow the native drag to - // start. - if (!this.internalDragElement_ || e.clientX < 0 || - e.clientX > window.innerWidth || e.clientY < 0 || - e.clientY > window.innerHeight) { - return; - } - - this.dropDestination_ = null; - - // Prevents a native drag from starting. - e.preventDefault(); - - this.autoScroller_.update(e); - - // On the first mousemove after a mousedown, calculate the items to drag. - // This can't be done in mousedown because the user may be shift-clicking - // an item. - if (!this.dragInfo_.isDragValid()) { - // If the mouse hasn't been moved far enough, defer to next mousemove. - if (Math.abs(this.mouseDownPos_.x - e.clientX) < DRAG_THRESHOLD && - Math.abs(this.mouseDownPos_.y - e.clientY) < DRAG_THRESHOLD) { - return; - } - - const dragData = this.calculateDragData_(); - if (!dragData) { - this.clearDragData_(); - return; - } - - this.dragInfo_.dragData = dragData; - } - - const state = bookmarks.Store.getInstance().data; - const items = this.dragInfo_.dragData.elements; - this.dndChip.showForItems( - e.clientX, e.clientY, items, - this.internalDragElement_ ? - state.nodes[this.internalDragElement_.itemId] : - items[0]); - - this.onDragOverCommon_(e); - }, - - /** - * This event fires when the mouse leaves the browser window (not the web - * content area). - * @private - */ - onMouseLeave_: function() { - if (!this.internalDragElement_) - return; - - this.startNativeDrag_(); - }, - - /** - * @private - */ - onMouseUp_: function() { - if (!this.internalDragElement_) - return; - - if (this.dropDestination_) { - // Complete the drag by moving all dragged items to the drop - // destination. - const dropInfo = this.calculateDropInfo_(this.dropDestination_); - const shouldHighlight = this.shouldHighlight_(this.dropDestination_); - - const movePromises = this.dragInfo_.dragData.elements.map((item) => { - return new Promise((resolve) => { - chrome.bookmarks.move( - item.id, { - parentId: dropInfo.parentId, - index: dropInfo.index == -1 ? undefined : dropInfo.index - }, - resolve); - }); - }); - - if (shouldHighlight) { - bookmarks.ApiListener.trackUpdatedItems(); - Promise.all(movePromises) - .then(() => bookmarks.ApiListener.highlightUpdatedItems()); - } - } - - this.clearDragData_(); - }, - - //////////////////////////////////////////////////////////////////////////// // DragEvent handlers: /** - * This should only fire when a mousemove goes from the content area to the - * browser chrome. * @private * @param {Event} e */ onDragStart_: function(e) { - // |e| will be for the originally dragged bookmark item which dragstart - // was disabled for due to mousemove's preventDefault. const dragElement = getDragElement(e.path); if (!dragElement) return; - // Prevent normal drags of all bookmark items. e.preventDefault(); - if (!this.startNativeDrag_()) + const dragData = this.calculateDragData_(dragElement); + if (!dragData) { + this.clearDragData_(); return; - - // If we are dragging a single link, we can do the *Link* effect. - // Otherwise, we only allow copy and move. - if (e.dataTransfer) { - const draggedNodes = this.dragInfo_.dragData.elements; - e.dataTransfer.effectAllowed = - draggedNodes.length == 1 && draggedNodes[0].url ? 'copyLink' : - 'copyMove'; } + + const state = bookmarks.Store.getInstance().data; + const draggedNodes = dragData.elements.map((item) => item.id); + const dragNodeIndex = draggedNodes.indexOf(dragElement.itemId); + assert(dragNodeIndex != -1); + + // TODO(calamity): account for touch. + chrome.bookmarkManagerPrivate.startDrag( + draggedNodes, dragNodeIndex, false); }, /** @private */ @@ -618,9 +404,9 @@ * @param {!Event} e */ onDrop_: function(e) { - if (this.dropDestination_) { - e.preventDefault(); + e.preventDefault(); + if (this.dropDestination_) { const dropInfo = this.calculateDropInfo_(this.dropDestination_); const index = dropInfo.index != -1 ? dropInfo.index : undefined; const shouldHighlight = this.shouldHighlight_(this.dropDestination_); @@ -633,7 +419,6 @@ shouldHighlight ? bookmarks.ApiListener.highlightUpdatedItems : undefined); } - this.clearDragData_(); }, @@ -650,28 +435,39 @@ * @param {Event} e */ onDragOver_: function(e) { - this.dropDestination_ = null; + // The default operation is to allow dropping links etc to do + // navigation. We never want to do that for the bookmark manager. + e.preventDefault(); - // This is necessary to actually trigger the 'none' effect, even though - // the event will have this set to 'none' already. - if (e.dataTransfer) - e.dataTransfer.dropEffect = 'none'; + this.dropDestination_ = null; // Allow normal DND on text inputs. if (e.path[0].tagName == 'INPUT') return; - // The default operation is to allow dropping links etc to do - // navigation. We never want to do that for the bookmark manager. - e.preventDefault(); - if (!this.dragInfo_.isDragValid()) return; - if (this.onDragOverCommon_(e) && e.dataTransfer) { - e.dataTransfer.dropEffect = - this.dragInfo_.isSameProfile() ? 'move' : 'copy'; + const state = bookmarks.Store.getInstance().data; + const items = this.dragInfo_.dragData.elements; + + const overElement = getBookmarkElement(e.path); + this.autoExpander_.update(e, overElement); + if (!overElement) { + this.dropIndicator_.finish(); + return; } + + // Now we know that we can drop. Determine if we will drop above, on or + // below based on mouse position etc. + this.dropDestination_ = + this.calculateDropDestination_(e.clientY, overElement); + if (!this.dropDestination_) { + this.dropIndicator_.finish(); + return; + } + + this.dropIndicator_.update(this.dropDestination_); }, /** @@ -683,14 +479,10 @@ }, //////////////////////////////////////////////////////////////////////////// - // Common drag methods: + // Helper methods: /** @private */ clearDragData_: function() { - this.dndChip.hide(); - this.autoScroller_.reset(); - this.internalDragElement_ = null; - this.mouseDownPos_ = null; this.autoExpander_.reset(); // Defer the clearing of the data so that the bookmark manager API's drop @@ -704,63 +496,6 @@ }, /** - * Starts a native drag by sending a message to the browser. - * @private - * @return {boolean} - */ - startNativeDrag_: function() { - const state = bookmarks.Store.getInstance().data; - - if (!this.dragInfo_.isDragValid()) - return false; - - const draggedNodes = - this.dragInfo_.dragData.elements.map((item) => item.id); - - // Clear the drag data here so that the chip is hidden. The native drag - // will return after the clearing and set up its data. - this.clearDragData_(); - - // TODO(calamity): account for touch. - chrome.bookmarkManagerPrivate.startDrag(draggedNodes, false); - - return true; - }, - - /** - * @private - * @param {Event} e - * @return {boolean} - */ - onDragOverCommon_: function(e) { - const state = bookmarks.Store.getInstance().data; - const items = this.dragInfo_.dragData.elements; - - const overElement = getBookmarkElement(e.path); - this.autoExpander_.update(e, overElement); - if (!overElement) { - this.dropIndicator_.finish(); - return false; - } - - // Now we know that we can drop. Determine if we will drop above, on or - // below based on mouse position etc. - this.dropDestination_ = - this.calculateDropDestination_(e.clientY, overElement); - if (!this.dropDestination_) { - this.dropIndicator_.finish(); - return false; - } - - this.dropIndicator_.update(this.dropDestination_); - - return true; - }, - - //////////////////////////////////////////////////////////////////////////// - // Other methods: - - /** * @param {DropDestination} dropDestination * @return {{parentId: string, index: number}} */ @@ -798,10 +533,11 @@ /** * Calculates which items should be dragged based on the initial drag item * and the current selection. Dragged items will end up selected. + * @param {!BookmarkElement} dragElement * @private */ - calculateDragData_: function() { - const dragId = this.internalDragElement_.itemId; + calculateDragData_: function(dragElement) { + const dragId = dragElement.itemId; const store = bookmarks.Store.getInstance(); const state = store.data; @@ -810,10 +546,10 @@ // Change selection to the dragged node if the node is not part of the // existing selection. - if (isBookmarkFolderNode(this.internalDragElement_) || + if (isBookmarkFolderNode(dragElement) || draggedNodes.indexOf(dragId) == -1) { store.dispatch(bookmarks.actions.deselectItems()); - if (!isBookmarkFolderNode(this.internalDragElement_)) { + if (!isBookmarkFolderNode(dragElement)) { store.dispatch(bookmarks.actions.selectItem(dragId, state, { clear: false, range: false, @@ -989,23 +725,10 @@ this.timerProxy_ = timerProxy; this.dropIndicator_.timerProxy = timerProxy; }, - - /** @return {BookmarksDndChipElement} */ - get dndChip() { - if (!this.chip_) { - this.chip_ = - /** @type {BookmarksDndChipElement} */ ( - document.createElement('bookmarks-dnd-chip')); - document.body.appendChild(this.chip_); - } - - return this.chip_; - }, }; return { AutoExpander: AutoExpander, - AutoScroller: AutoScroller, DNDManager: DNDManager, DragInfo: DragInfo, DropIndicator: DropIndicator,
diff --git a/chrome/browser/resources/md_extensions/runtime_host_permissions.html b/chrome/browser/resources/md_extensions/runtime_host_permissions.html index 3a09d0be..25ebeda 100644 --- a/chrome/browser/resources/md_extensions/runtime_host_permissions.html +++ b/chrome/browser/resources/md_extensions/runtime_host_permissions.html
@@ -81,7 +81,7 @@ </div> <ul id="hosts"> <template is="dom-repeat" - items="[[permissions.runtimeHostPermissions]]"> + items="[[getRuntimeHosts_(permissions.specificSiteControls)]]"> <li> <div>[[item]]</div> <paper-icon-button-light class="icon-more-vert">
diff --git a/chrome/browser/resources/md_extensions/runtime_host_permissions.js b/chrome/browser/resources/md_extensions/runtime_host_permissions.js index 0463c047..18d98e11 100644 --- a/chrome/browser/resources/md_extensions/runtime_host_permissions.js +++ b/chrome/browser/resources/md_extensions/runtime_host_permissions.js
@@ -101,8 +101,7 @@ /** @type {chrome.developerPrivate.HostAccess} */ (select.value); if (access == chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES && - (!this.permissions.runtimeHostPermissions || - this.permissions.runtimeHostPermissions.length == 0)) { + !this.permissions.specificSiteControls) { // If the user is transitioning to the "on specific sites" option, show // the "add host" dialog. This serves two purposes: // - The user is prompted to add a host immediately, since otherwise @@ -129,6 +128,24 @@ }, /** + * Returns the granted host permissions as a sorted set of strings. + * @return {!Array<string>} + * @private + */ + getRuntimeHosts_: function() { + if (!this.permissions.specificSiteControls) + return []; + + // Only show granted hosts in the list. + // TODO(devlin): For extensions that request a finite set of hosts, + // display them in a toggle list. https://crbug.com/891803. + return this.permissions.specificSiteControls.hosts + .filter(control => control.granted) + .map(control => control.host) + .sort(); + }, + + /** * @param {Event} e * @private */
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html index 216ff5d5..2e8fb6c 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.html +++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -123,7 +123,8 @@ restamp> <settings-section page-title="$i18n{multidevicePageTitle}" section="multidevice"> - <settings-multidevice-page></settings-multidevice-page> + <settings-multidevice-page prefs="{{prefs}}"> + </settings-multidevice-page> </settings-section> </template> </if>
diff --git a/chrome/browser/resources/settings/controls/settings_slider.html b/chrome/browser/resources/settings/controls/settings_slider.html index d6046aa..b30ee91 100644 --- a/chrome/browser/resources/settings/controls/settings_slider.html +++ b/chrome/browser/resources/settings/controls/settings_slider.html
@@ -53,7 +53,8 @@ </template> <div class="outer"> <cr-slider id="slider" disabled$="[[disableSlider_]]" ticks="[[ticks]]" - on-value-changed="onSliderChanged_" max="[[max]]" min="[[min]]"> + on-value-changed="onSliderChanged_" max="[[max]]" min="[[min]]" + update-value-instantly="[[updateValueInstantly]]"> </cr-slider> <div id="labels" disabled$="[[disableSlider_]]"> <div id="label-begin">[[labelMin]]</div>
diff --git a/chrome/browser/resources/settings/controls/settings_slider.js b/chrome/browser/resources/settings/controls/settings_slider.js index d9f79075..0b62ed330 100644 --- a/chrome/browser/resources/settings/controls/settings_slider.js +++ b/chrome/browser/resources/settings/controls/settings_slider.js
@@ -54,6 +54,11 @@ type: Boolean, }, + updateValueInstantly: { + type: Boolean, + value: true, + }, + loaded_: Boolean, },
diff --git a/chrome/browser/resources/settings/device_page/display.js b/chrome/browser/resources/settings/device_page/display.js index f10aec3..cbe128d 100644 --- a/chrome/browser/resources/settings/device_page/display.js +++ b/chrome/browser/resources/settings/device_page/display.js
@@ -203,6 +203,7 @@ this.displayChangedListener_); this.getDisplayInfo_(); + this.$.displaySizeSlider.updateValueInstantly = false; }, /** @override */
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.js b/chrome/browser/resources/settings/internet_page/network_summary_item.js index b4a8f88..447b56be 100644 --- a/chrome/browser/resources/settings/internet_page/network_summary_item.js +++ b/chrome/browser/resources/settings/internet_page/network_summary_item.js
@@ -102,7 +102,7 @@ * @private */ getConnectionStateText_: function(networkState) { - const state = networkState.ConnectionState; + const state = networkState ? networkState.ConnectionState : null; if (!state) return ''; const name = CrOnc.getNetworkName(networkState); @@ -130,8 +130,9 @@ * @private */ showPolicyIndicator_: function(activeNetworkState) { - return activeNetworkState.ConnectionState == - CrOnc.ConnectionState.CONNECTED || + return (activeNetworkState !== undefined && + activeNetworkState.ConnectionState == + CrOnc.ConnectionState.CONNECTED) || this.isPolicySource(activeNetworkState.Source); },
diff --git a/chrome/browser/resources/settings/multidevice_page/BUILD.gn b/chrome/browser/resources/settings/multidevice_page/BUILD.gn index 30149cc..9f7fc350 100644 --- a/chrome/browser/resources/settings/multidevice_page/BUILD.gn +++ b/chrome/browser/resources/settings/multidevice_page/BUILD.gn
@@ -12,6 +12,7 @@ ":multidevice_feature_item", ":multidevice_feature_toggle", ":multidevice_page", + ":multidevice_smartlock_subpage", ":multidevice_subpage", ":multidevice_tether_item", ] @@ -65,6 +66,16 @@ ] } +js_library("multidevice_smartlock_subpage") { + deps = [ + ":multidevice_constants", + ":multidevice_feature_behavior", + "../prefs:prefs_behavior", + "//ui/webui/resources/cr_elements/cr_radio_button:cr_radio_button", + "//ui/webui/resources/js:cr", + ] +} + js_library("multidevice_subpage") { deps = [ ":multidevice_constants",
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_page.html b/chrome/browser/resources/settings/multidevice_page/multidevice_page.html index 5001f6bc..3f6c521 100644 --- a/chrome/browser/resources/settings/multidevice_page/multidevice_page.html +++ b/chrome/browser/resources/settings/multidevice_page/multidevice_page.html
@@ -19,6 +19,7 @@ <link rel="import" href="multidevice_constants.html"> <link rel="import" href="multidevice_feature_behavior.html"> <link rel="import" href="multidevice_feature_toggle.html"> +<link rel="import" href="multidevice_smartlock_subpage.html"> <link rel="import" href="multidevice_subpage.html"> <dom-module id="settings-multidevice-page"> @@ -91,9 +92,18 @@ <template is="dom-if" route-path="/multidevice/features" restamp> <settings-subpage associated-control="[[$$('#multidevice-item')]]" page-title="[[pageContentData.hostDeviceName]]"> - <settings-multidevice-subpage - page-content-data="[[pageContentData]]"> - </settings-multidevice-subpage> + <settings-multidevice-subpage + page-content-data="[[pageContentData]]"> + </settings-multidevice-subpage> + </settings-subpage> + </template> + <template is="dom-if" route-path="/multidevice/features/smartLock" + restamp> + <settings-subpage page-title="$i18n{easyUnlockSectionTitle}"> + <settings-multidevice-smartlock-subpage + prefs="{{prefs}}" + page-content-data="[[pageContentData]]"> + </settings-multidevice-smartlock-subpage> </settings-subpage> </template> </settings-animated-pages>
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_page.js b/chrome/browser/resources/settings/multidevice_page/multidevice_page.js index 5a8aa974..447280a 100644 --- a/chrome/browser/resources/settings/multidevice_page/multidevice_page.js +++ b/chrome/browser/resources/settings/multidevice_page/multidevice_page.js
@@ -14,6 +14,9 @@ behaviors: [MultiDeviceFeatureBehavior, WebUIListenerBehavior], properties: { + /** Preferences state. */ + prefs: {type: Object}, + /** * A Map specifying which element should be focused when exiting a subpage. * The key of the map holds a settings.Route path, and the value holds a
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.html b/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.html new file mode 100644 index 0000000..954815f --- /dev/null +++ b/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.html
@@ -0,0 +1,55 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html"> +<link rel="import" href="multidevice_constants.html"> +<link rel="import" href="multidevice_feature_behavior.html"> +<link rel="import" href="multidevice_feature_toggle.html"> +<link rel="import" href="../i18n_setup.html"> +<link rel="import" href="../prefs/prefs.html"> +<link rel="import" href="../settings_shared_css.html"> + +<dom-module id="settings-multidevice-smartlock-subpage"> + <template> + <style include="settings-shared"></style> + <div class="settings-box first"> + <!-- TODO(jhawkins): Remove this status text and move the toggle into + the subpage header section. --> + <div class="start"> + <template is="dom-if" if="[[smartLockEnabled_]]" restamp> + $i18n{multideviceEnabled} + </template> + <template is="dom-if" if="[[!smartLockEnabled_]]" restamp> + $i18n{multideviceDisabled} + </template> + </div> + <settings-multidevice-feature-toggle + feature="[[MultiDeviceFeature.SMART_LOCK]]" + page-content-data="[[pageContentData]]"> + </settings-multidevice-feature-toggle> + </div> + <div class="settings-box first line-only"> + <h2 class="start first"> + $i18n{multideviceSmartLockOptions} + </h2> + </div> + <iron-collapse opened="[[smartLockEnabled_]]"> + <div class="list-frame"> + <paper-radio-group + selected="[[smartLockSignInEnabled_]]" + selectable="cr-radio-button"> + <cr-radio-button + name="disabled" + class="list-item underbar" + label="$i18n{easyUnlockUnlockDeviceOnly}"> + </cr-radio-button> + <cr-radio-button + name="enabled" + class="list-item" + label="$i18n{easyUnlockUnlockDeviceAndAllowSignin}"> + </cr-radio-button> + </paper-radio-group> + </div> + </iron-collapse> + </template> + <script src="multidevice_smartlock_subpage.js"></script> +</dom-module> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.js b/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.js new file mode 100644 index 0000000..04ff48b --- /dev/null +++ b/chrome/browser/resources/settings/multidevice_page/multidevice_smartlock_subpage.js
@@ -0,0 +1,93 @@ +// 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. + +/** + * @fileoverview + * Subpage of settings-multidevice-feature for managing the Smart Lock feature. + */ +cr.exportPath('settings'); + +cr.define('settings', function() { + /** + * The state of the preference controlling Smart Lock's ability to sign-in the + * user. + * @enum {string} + */ + SignInEnabledState = { + ENABLED: 'enabled', + DISABLED: 'disabled', + }; + + /** @const {string} */ + SmartLockSignInEnabledPrefName = 'proximity_auth.is_chromeos_login_enabled'; + + return { + SignInEnabledState: SignInEnabledState, + SmartLockSignInEnabledPrefName: SmartLockSignInEnabledPrefName, + }; +}); + +Polymer({ + is: 'settings-multidevice-smartlock-subpage', + + behaviors: [ + MultiDeviceFeatureBehavior, + ], + + properties: { + /** Preferences state. */ + prefs: {type: Object}, + + /** @type {?SettingsRoutes} */ + routes: { + type: Object, + value: settings.routes, + }, + + /** + * True if Smart Lock is enabled. + * @private + */ + smartLockEnabled_: { + type: Boolean, + computed: 'computeIsSmartLockEnabled_(pageContentData)', + }, + + /** + * Whether Smart Lock may be used to sign-in the user (as opposed to only + * being able to unlock the user's screen). + * @private {!settings.SignInEnabledState} + */ + smartLockSignInEnabled_: { + type: Object, + value: settings.SignInEnabledState.DISABLED, + }, + }, + + observers: [ + 'updateSmartLockSignInEnabled_(prefs.' + + settings.SmartLockSignInEnabledPrefName + '.value)', + ], + + /** + * Returns true if Smart Lock is an enabled feature. + * @return {boolean} + * @private + */ + computeIsSmartLockEnabled_: function() { + return !!this.pageContentData && + this.getFeatureState(settings.MultiDeviceFeature.SMART_LOCK) == + settings.MultiDeviceFeatureState.ENABLED_BY_USER; + }, + + /** + * Updates the state of Smart Lock 'sign-in enabled' toggle. + * @private + */ + updateSmartLockSignInEnabled_: function(enabled) { + this.smartLockSignInEnabled_ = enabled ? + settings.SignInEnabledState.ENABLED : + settings.SignInEnabledState.DISABLED; + }, +});
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html index 5b45963..9aaef19 100644 --- a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html +++ b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html
@@ -66,7 +66,7 @@ <settings-multidevice-feature-item id="smartLockItem" feature="[[MultiDeviceFeature.SMART_LOCK]]" page-content-data="[[pageContentData]]" - subpage-route="[[routes.LOCK_SCREEN]]"> + subpage-route="[[routes.SMART_LOCK]]"> </settings-multidevice-feature-item> </template> <template is="dom-if"
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js index 866453b..fa4f50d9 100644 --- a/chrome/browser/resources/settings/route.js +++ b/chrome/browser/resources/settings/route.js
@@ -94,6 +94,7 @@ * SITE_SETTINGS_UNSANDBOXED_PLUGINS: (undefined|!settings.Route), * SITE_SETTINGS_USB_DEVICES: (undefined|!settings.Route), * SITE_SETTINGS_ZOOM_LEVELS: (undefined|!settings.Route), + * SMART_LOCK: (undefined|!settings.Route), * SMB_SHARES: (undefined|!settings.Route), * STORAGE: (undefined|!settings.Route), * STYLUS: (undefined|!settings.Route), @@ -238,6 +239,8 @@ r.MULTIDEVICE = r.BASIC.createSection('/multidevice', 'multidevice'); r.MULTIDEVICE_FEATURES = r.MULTIDEVICE.createChild('/multidevice/features'); + r.SMART_LOCK = + r.MULTIDEVICE_FEATURES.createChild('/multidevice/features/smartLock'); // </if> if (pageVisibility.appearance !== false) {
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index 3b2676828..73e58e8 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -1357,6 +1357,12 @@ <structure name="IDR_SETTINGS_MULTIDEVICE_PAGE_JS" file="multidevice_page/multidevice_page.js" type="chrome_html" /> + <structure name="IDR_SETTINGS_MULTIDEVICE_SMARTLOCK_SUBPAGE_HTML" + file="multidevice_page/multidevice_smartlock_subpage.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_MULTIDEVICE_SMARTLOCK_SUBPAGE_JS" + file="multidevice_page/multidevice_smartlock_subpage.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_MULTIDEVICE_SUBPAGE_HTML" file="multidevice_page/multidevice_subpage.html" type="chrome_html" />
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html b/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html index 06f746f..40789091 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html +++ b/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email.html
@@ -3,8 +3,6 @@ <head> <meta charset="utf-8"> <title>$i18n{headerText}</title> - <script src="chrome://resources/js/load_time_data.js"></script> - <script src="strings.js"></script> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://welcome/email/email_chooser.html"> <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.html b/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.html index eeee7f64..b9d49f9 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.html +++ b/chrome/browser/resources/welcome/onboarding_welcome/email/nux_email_proxy.html
@@ -1,2 +1,3 @@ <link rel="import" href="chrome://resources/html/cr.html"> +<link rel="import" href="../shared/i18n_setup.html"> <script src="nux_email_proxy.js"></script> \ No newline at end of file
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/shared/i18n_setup.html b/chrome/browser/resources/welcome/onboarding_welcome/shared/i18n_setup.html new file mode 100644 index 0000000..fa9610d --- /dev/null +++ b/chrome/browser/resources/welcome/onboarding_welcome/shared/i18n_setup.html
@@ -0,0 +1,2 @@ +<script src="chrome://resources/js/load_time_data.js"></script> +<script src="../strings.js"></script> \ No newline at end of file
diff --git a/chrome/browser/search/url_validity_checker_factory.cc b/chrome/browser/search/url_validity_checker_factory.cc new file mode 100644 index 0000000..ae29f5e4 --- /dev/null +++ b/chrome/browser/search/url_validity_checker_factory.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 "chrome/browser/search/url_validity_checker_factory.h" + +#include <memory> + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/net/system_network_context_manager.h" +#include "content/public/browser/browser_thread.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" + +// static +UrlValidityChecker* UrlValidityCheckerFactory::GetInstance() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + static base::LazyInstance<UrlValidityCheckerFactory>::DestructorAtExit + instance = LAZY_INSTANCE_INITIALIZER; + return &(instance.Get().url_validity_checker_); +} + +UrlValidityCheckerFactory::UrlValidityCheckerFactory() + : url_validity_checker_(g_browser_process->system_network_context_manager() + ->GetSharedURLLoaderFactory()) {} + +UrlValidityCheckerFactory::~UrlValidityCheckerFactory() {}
diff --git a/chrome/browser/search/url_validity_checker_factory.h b/chrome/browser/search/url_validity_checker_factory.h new file mode 100644 index 0000000..1ebd79d0 --- /dev/null +++ b/chrome/browser/search/url_validity_checker_factory.h
@@ -0,0 +1,30 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SEARCH_URL_VALIDITY_CHECKER_FACTORY_H_ +#define CHROME_BROWSER_SEARCH_URL_VALIDITY_CHECKER_FACTORY_H_ + +#include "base/lazy_instance.h" +#include "base/macros.h" +#include "components/search/url_validity_checker_impl.h" + +// Singleton that owns a single UrlValidityCheckerImpl instance. Should only be +// called from the UI thread. +class UrlValidityCheckerFactory { + public: + static UrlValidityChecker* GetInstance(); + + private: + friend struct base::LazyInstanceTraitsBase<UrlValidityCheckerFactory>; + + UrlValidityCheckerFactory(); + ~UrlValidityCheckerFactory(); + + // The only instance that exists. + UrlValidityCheckerImpl url_validity_checker_; + + DISALLOW_COPY_AND_ASSIGN(UrlValidityCheckerFactory); +}; + +#endif // CHROME_BROWSER_SEARCH_URL_VALIDITY_CHECKER_FACTORY_H_
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc index 634ee698..c1998b8 100644 --- a/chrome/browser/shell_integration_win.cc +++ b/chrome/browser/shell_integration_win.cc
@@ -159,13 +159,22 @@ win::MigrateShortcutsInPathInternal(chrome_exe, pins_path); } +// Windows treats a given scheme as an Internet scheme only if its registry +// entry has a "URL Protocol" key. Check this, otherwise we allow ProgIDs to be +// used as custom protocols which leads to security bugs. +bool IsValidCustomProtocol(const base::string16& scheme) { + if (scheme.empty()) + return false; + base::win::RegKey cmd_key(HKEY_CLASSES_ROOT, scheme.c_str(), KEY_QUERY_VALUE); + return cmd_key.Valid() && cmd_key.HasValue(L"URL Protocol"); +} + // Windows 8 introduced a new protocol->executable binding system which cannot // be retrieved in the HKCR registry subkey method implemented below. We call // AssocQueryString with the new Win8-only flag ASSOCF_IS_PROTOCOL instead. base::string16 GetAppForProtocolUsingAssocQuery(const GURL& url) { - base::string16 url_scheme = base::ASCIIToUTF16(url.scheme()); - // Don't attempt to query protocol association on an empty string. - if (url_scheme.empty()) + const base::string16 url_scheme = base::ASCIIToUTF16(url.scheme()); + if (!IsValidCustomProtocol(url_scheme)) return base::string16(); // Query AssocQueryString for a human-readable description of the program @@ -174,12 +183,9 @@ // an unknown external protocol. wchar_t out_buffer[1024]; DWORD buffer_size = arraysize(out_buffer); - HRESULT hr = AssocQueryString(ASSOCF_IS_PROTOCOL, - ASSOCSTR_FRIENDLYAPPNAME, - url_scheme.c_str(), - NULL, - out_buffer, - &buffer_size); + HRESULT hr = + AssocQueryString(ASSOCF_IS_PROTOCOL, ASSOCSTR_FRIENDLYAPPNAME, + url_scheme.c_str(), NULL, out_buffer, &buffer_size); if (FAILED(hr)) { DLOG(WARNING) << "AssocQueryString failed!"; return base::string16(); @@ -188,11 +194,13 @@ } base::string16 GetAppForProtocolUsingRegistry(const GURL& url) { - base::string16 command_to_launch; + const base::string16 url_scheme = base::ASCIIToUTF16(url.scheme()); + if (!IsValidCustomProtocol(url_scheme)) + return base::string16(); // First, try and extract the application's display name. - base::string16 cmd_key_path = base::ASCIIToUTF16(url.scheme()); - base::win::RegKey cmd_key_name(HKEY_CLASSES_ROOT, cmd_key_path.c_str(), + base::string16 command_to_launch; + base::win::RegKey cmd_key_name(HKEY_CLASSES_ROOT, url_scheme.c_str(), KEY_READ); if (cmd_key_name.ReadValue(NULL, &command_to_launch) == ERROR_SUCCESS && !command_to_launch.empty()) { @@ -201,7 +209,7 @@ // Otherwise, parse the command line in the registry, and return the basename // of the program path if it exists. - cmd_key_path = base::ASCIIToUTF16(url.scheme() + "\\shell\\open\\command"); + const base::string16 cmd_key_path = url_scheme + L"\\shell\\open\\command"; base::win::RegKey cmd_key_exe(HKEY_CLASSES_ROOT, cmd_key_path.c_str(), KEY_READ); if (cmd_key_exe.ReadValue(NULL, &command_to_launch) == ERROR_SUCCESS) { @@ -581,10 +589,9 @@ } base::string16 GetApplicationNameForProtocol(const GURL& url) { - base::string16 application_name; // Windows 8 or above has a new protocol association query. if (base::win::GetVersion() >= base::win::VERSION_WIN8) { - application_name = GetAppForProtocolUsingAssocQuery(url); + base::string16 application_name = GetAppForProtocolUsingAssocQuery(url); if (!application_name.empty()) return application_name; }
diff --git a/chrome/browser/speech/tts_controller.h b/chrome/browser/speech/tts_controller.h index 6aba287..1989e2b 100644 --- a/chrome/browser/speech/tts_controller.h +++ b/chrome/browser/speech/tts_controller.h
@@ -13,6 +13,7 @@ #include "base/memory/singleton.h" #include "base/memory/weak_ptr.h" +#include "base/observer_list_types.h" #include "url/gurl.h" class Utterance; @@ -113,9 +114,8 @@ // Class that wants to be notified when the set of // voices has changed. -class VoicesChangedDelegate { +class VoicesChangedDelegate : public base::CheckedObserver { public: - virtual ~VoicesChangedDelegate() {} virtual void OnVoicesChanged() = 0; };
diff --git a/chrome/browser/speech/tts_controller_impl.cc b/chrome/browser/speech/tts_controller_impl.cc index 9ec2bdf..46ea468 100644 --- a/chrome/browser/speech/tts_controller_impl.cc +++ b/chrome/browser/speech/tts_controller_impl.cc
@@ -622,20 +622,18 @@ if (!platform_impl_) return; - for (auto iter = voices_changed_delegates_.begin(); - iter != voices_changed_delegates_.end(); ++iter) { - (*iter)->OnVoicesChanged(); - } + for (auto& delegate : voices_changed_delegates_) + delegate.OnVoicesChanged(); } void TtsControllerImpl::AddVoicesChangedDelegate( VoicesChangedDelegate* delegate) { - voices_changed_delegates_.insert(delegate); + voices_changed_delegates_.AddObserver(delegate); } void TtsControllerImpl::RemoveVoicesChangedDelegate( VoicesChangedDelegate* delegate) { - voices_changed_delegates_.erase(delegate); + voices_changed_delegates_.RemoveObserver(delegate); } void TtsControllerImpl::RemoveUtteranceEventDelegate(
diff --git a/chrome/browser/speech/tts_controller_impl.h b/chrome/browser/speech/tts_controller_impl.h index 49a22aa..e8b574e 100644 --- a/chrome/browser/speech/tts_controller_impl.h +++ b/chrome/browser/speech/tts_controller_impl.h
@@ -102,7 +102,7 @@ base::queue<Utterance*> utterance_queue_; // A set of delegates that want to be notified when the voices change. - std::set<VoicesChangedDelegate*> voices_changed_delegates_; + base::ObserverList<VoicesChangedDelegate> voices_changed_delegates_; // A pointer to the platform implementation of text-to-speech, for // dependency injection.
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc index 3a36371..982cd6e 100644 --- a/chrome/browser/ssl/ssl_browsertest.cc +++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -7169,7 +7169,7 @@ ui_test_utils::NavigateToURL(browser(), url); console_observer.Wait(); EXPECT_TRUE( - base::MatchPattern(console_observer.message(), "*distrusted in M70*")); + base::MatchPattern(console_observer.message(), "*distrusted very soon*")); } // Tests that the Symantec console message is logged for subresources, but caps
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc index 45a830f..cd5c3e9 100644 --- a/chrome/browser/themes/theme_properties.cc +++ b/chrome/browser/themes/theme_properties.cc
@@ -168,7 +168,7 @@ return incognito ? gfx::kGoogleGrey100 : gfx::kGoogleGrey800; case ThemeProperties::COLOR_BOOKMARK_TEXT: - return incognito ? gfx::kGoogleGrey100 : gfx::kGoogleGrey700; + return incognito ? gfx::kGoogleGrey100 : gfx::kGoogleGrey800; case ThemeProperties::COLOR_TAB_CLOSE_BUTTON_ACTIVE: case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON:
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 9df30a8..266fd8b 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -132,6 +132,8 @@ "cocoa/themed_window.mm", "cocoa/touchbar/credit_card_autofill_touch_bar_controller.h", "cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm", + "cocoa/touchbar/text_suggestions_touch_bar_controller.h", + "cocoa/touchbar/text_suggestions_touch_bar_controller.mm", "cocoa/touchbar/web_textfield_touch_bar_controller.h", "cocoa/touchbar/web_textfield_touch_bar_controller.mm", "cocoa/url_drop_target.h", @@ -2854,6 +2856,8 @@ "views/tabs/tab_strip_controller.h", "views/tabs/tab_strip_layout.cc", "views/tabs/tab_strip_layout.h", + "views/tabs/tab_style.cc", + "views/tabs/tab_style.h", "views/tabs/window_finder.h", "views/task_manager_view.cc", "views/task_manager_view.h",
diff --git a/chrome/browser/ui/app_list/arc/arc_app_icon.cc b/chrome/browser/ui/app_list/arc/arc_app_icon.cc index 3cc1d8a..ddbccc65 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_icon.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_icon.cc
@@ -73,17 +73,19 @@ ReadResult(bool error, bool request_to_install, ui::ScaleFactor scale_factor, + bool resize_allowed, std::string unsafe_icon_data) : error(error), request_to_install(request_to_install), scale_factor(scale_factor), - unsafe_icon_data(unsafe_icon_data) { - } + resize_allowed(resize_allowed), + unsafe_icon_data(unsafe_icon_data) {} - bool error; - bool request_to_install; - ui::ScaleFactor scale_factor; - std::string unsafe_icon_data; + const bool error; + const bool request_to_install; + const ui::ScaleFactor scale_factor; + const bool resize_allowed; + const std::string unsafe_icon_data; }; //////////////////////////////////////////////////////////////////////////////// @@ -166,7 +168,8 @@ class ArcAppIcon::DecodeRequest : public ImageDecoder::ImageRequest { public: DecodeRequest(const base::WeakPtr<ArcAppIcon>& host, - const ArcAppIconDescriptor& descriptor); + const ArcAppIconDescriptor& descriptor, + bool resize_allowed); ~DecodeRequest() override; // ImageDecoder::ImageRequest @@ -176,6 +179,7 @@ private: base::WeakPtr<ArcAppIcon> host_; const ArcAppIconDescriptor descriptor_; + const bool resize_allowed_; DISALLOW_COPY_AND_ASSIGN(DecodeRequest); }; @@ -184,11 +188,11 @@ // ArcAppIcon::DecodeRequest ArcAppIcon::DecodeRequest::DecodeRequest(const base::WeakPtr<ArcAppIcon>& host, - const ArcAppIconDescriptor& descriptor) - : host_(host), descriptor_(descriptor) {} + const ArcAppIconDescriptor& descriptor, + bool resize_allowed) + : host_(host), descriptor_(descriptor), resize_allowed_(resize_allowed) {} -ArcAppIcon::DecodeRequest::~DecodeRequest() { -} +ArcAppIcon::DecodeRequest::~DecodeRequest() = default; void ArcAppIcon::DecodeRequest::OnImageDecoded(const SkBitmap& bitmap) { DCHECK(!bitmap.isNull() && !bitmap.empty()); @@ -198,15 +202,20 @@ const int expected_dim = descriptor_.GetSizeInPixels(); if (bitmap.width() != expected_dim || bitmap.height() != expected_dim) { - VLOG(2) << "Decoded ARC icon has unexpected dimension " << bitmap.width() - << "x" << bitmap.height() << ". Expected " << expected_dim << "."; - - host_->MaybeRequestIcon(descriptor_.scale_factor); - host_->DiscardDecodeRequest(this); - return; + if (!resize_allowed_) { + VLOG(2) << "Decoded ARC icon has unexpected dimension " << bitmap.width() + << "x" << bitmap.height() << ". Expected " << expected_dim << "."; + host_->MaybeRequestIcon(descriptor_.scale_factor); + } else { + host_->Update(descriptor_.scale_factor, + skia::ImageOperations::Resize( + bitmap, skia::ImageOperations::RESIZE_BEST, + expected_dim, expected_dim)); + } + } else { + host_->Update(descriptor_.scale_factor, bitmap); } - host_->Update(descriptor_.scale_factor, bitmap); host_->DiscardDecodeRequest(this); } @@ -295,14 +304,19 @@ DCHECK(!path.empty()); base::FilePath path_to_read; + // Allow resizing only for default app icons. + bool resize_allowed; if (base::PathExists(path)) { path_to_read = path; + resize_allowed = false; } else { if (default_app_path.empty() || !base::PathExists(default_app_path)) { - return std::make_unique<ArcAppIcon::ReadResult>(false, true, scale_factor, - std::string()); + return std::make_unique<ArcAppIcon::ReadResult>( + false /* error */, true /* request_to_install */, scale_factor, + false /* resize_allowed */, std::string() /* unsafe_icon_data */); } path_to_read = default_app_path; + resize_allowed = true; } bool request_to_install = path_to_read != path; @@ -317,11 +331,13 @@ // on cached icon file. Send request to re install the icon. request_to_install |= unsafe_icon_data.empty(); return std::make_unique<ArcAppIcon::ReadResult>( - true, request_to_install, scale_factor, std::string()); + true /* error */, request_to_install, scale_factor, + false /* resize_allowed */, std::string() /* unsafe_icon_data */); } return std::make_unique<ArcAppIcon::ReadResult>( - false, request_to_install, scale_factor, unsafe_icon_data); + false /* error */, request_to_install, scale_factor, resize_allowed, + unsafe_icon_data); } void ArcAppIcon::OnIconRead( @@ -334,8 +350,8 @@ if (!read_result->unsafe_icon_data.empty()) { decode_requests_.emplace_back(std::make_unique<DecodeRequest>( weak_ptr_factory_.GetWeakPtr(), - ArcAppIconDescriptor(resource_size_in_dip_, - read_result->scale_factor))); + ArcAppIconDescriptor(resource_size_in_dip_, read_result->scale_factor), + read_result->resize_allowed)); if (disable_safe_decoding_for_testing) { SkBitmap bitmap; if (!read_result->unsafe_icon_data.empty() &&
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc index aaf98f6..b63d08d0 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -174,6 +174,22 @@ info1.launchable != info2.launchable; } +// We have only fixed icon dimensions for default apps, 32, 48 and 64. If +// requested dimension does not exist, use bigger one that can be downsized. +// In case requested dimension is bigger than 64, use largest possible size that +// can be upsized. +ArcAppIconDescriptor MapDefaultAppIconDescriptor( + const ArcAppIconDescriptor& descriptor) { + int default_app_dip_size; + if (descriptor.dip_size <= 32) + default_app_dip_size = 32; + else if (descriptor.dip_size <= 48) + default_app_dip_size = 48; + else + default_app_dip_size = 64; + return ArcAppIconDescriptor(default_app_dip_size, descriptor.scale_factor); +} + // Whether skip install_time for comparing two |AppInfo|. bool ignore_compare_app_info_install_time = false; @@ -379,7 +395,8 @@ if (!default_app || default_app->app_path.empty()) return base::FilePath(); - return default_app->app_path.AppendASCII(descriptor.GetName()); + return default_app->app_path.AppendASCII( + MapDefaultAppIconDescriptor(descriptor).GetName()); } base::FilePath ArcAppListPrefs::GetIconPath(
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc index 5ddd291..9e445bd 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -2318,6 +2318,28 @@ icon_loader.reset(); } +// Validates that default app icon can be loaded for non-default dips, that do +// not exist in Chrome image. +TEST_P(ArcAppLauncherForDefaulAppTest, AppIconNonDefaultDip) { + ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get()); + ASSERT_NE(nullptr, prefs); + + ASSERT_FALSE(fake_default_apps().empty()); + const arc::mojom::AppInfo& app = fake_default_apps()[0]; + const std::string app_id = ArcAppTest::GetAppId(app); + + // Icon can be only fetched after app is registered in the system. + arc_test()->WaitForDefaultApps(); + + FakeAppIconLoaderDelegate icon_delegate; + // 17 should never be a default dip size. + std::unique_ptr<ArcAppIconLoader> icon_loader = + std::make_unique<ArcAppIconLoader>(profile(), 17, &icon_delegate); + icon_loader->FetchImage(app_id); + icon_delegate.WaitForIconUpdates(ui::GetSupportedScaleFactors().size()); + icon_loader.reset(); +} + TEST_P(ArcAppLauncherForDefaulAppTest, AppLauncherForDefaultApps) { ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get()); ASSERT_NE(nullptr, prefs);
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc b/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc index 93d80a3..1293ff45 100644 --- a/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc +++ b/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc
@@ -158,6 +158,15 @@ return; } + // TODO(jkardatzke): Remove this code for M72. This is a workaround to deal + // with a bug where we were caching the wrong resolution of the icons and they + // looked really bad. This only existed on dev channel, so there's limited + // reach of it, and after everyone has upgraded we can remove this check. + // crbug.com/891588 + if (bitmap.width() < expected_dim || bitmap.height() < expected_dim) { + host_->MaybeRequestIcon(scale_factor_); + } + // We won't always get back from Crostini the icon size we asked for, so it // is expected that sometimes we need to rescale it. SkBitmap resized_image = skia::ImageOperations::Resize( @@ -220,6 +229,15 @@ if (!registry_service_) return; + // TODO(jkardatzke): Remove this for M-72, this is here temporarily to prevent + // continually requesting updated icons if there are not larger size ones + // available in Linux for that app. + // crbug.com/891588 + if (already_requested_icons_.find(scale_factor) != + already_requested_icons_.end()) + return; + already_requested_icons_.insert(scale_factor); + // CrostiniRegistryService notifies CrostiniAppModelBuilder via Observer when // icon is ready and CrostiniAppModelBuilder refreshes the icon of the // corresponding item by calling LoadScaleFactor.
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_icon.h b/chrome/browser/ui/app_list/crostini/crostini_app_icon.h index a222687..7b611ed3 100644 --- a/chrome/browser/ui/app_list/crostini/crostini_app_icon.h +++ b/chrome/browser/ui/app_list/crostini/crostini_app_icon.h
@@ -92,6 +92,10 @@ gfx::ImageSkia image_skia_; + // TODO(jkardatzke): Remove this for M-72, it's to cleanup from + // crbug.com/891588 + std::set<ui::ScaleFactor> already_requested_icons_; + // Contains pending image decode requests. std::vector<std::unique_ptr<DecodeRequest>> decode_requests_;
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc index e38e397..e348cc4 100644 --- a/chrome/browser/ui/app_list/search/omnibox_result.cc +++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -89,6 +89,7 @@ case AutocompleteMatchType::PHYSICAL_WEB_OVERFLOW_DEPRECATED: case AutocompleteMatchType::TAB_SEARCH_DEPRECATED: case AutocompleteMatchType::DOCUMENT_SUGGESTION: + case AutocompleteMatchType::PEDAL: return kIcDomainIcon; case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED:
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc index 657bb19..61c8619 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -13,6 +13,7 @@ #include "ash/public/cpp/shelf_item.h" #include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shelf_prefs.h" +#include "ash/public/cpp/window_animation_types.h" #include "ash/public/interfaces/constants.mojom.h" #include "ash/shell.h" #include "base/strings/pattern.h" @@ -520,12 +521,19 @@ return ash::SHELF_ACTION_WINDOW_ACTIVATED; } + AppListClientImpl* app_list_client = AppListClientImpl::GetInstance(); if (window->IsActive() && allow_minimize && - !AppListClientImpl::GetInstance()->app_list_target_visibility()) { + !(app_list_client && app_list_client->app_list_target_visibility())) { window->Minimize(); return ash::SHELF_ACTION_WINDOW_MINIMIZED; } + if (app_list_client && app_list_client->IsHomeLauncherEnabledInTabletMode()) { + // Run slide down animation to show the window. + wm::SetWindowVisibilityAnimationType( + native_window, ash::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_SLIDE_DOWN); + } + window->Show(); window->Activate(); return ash::SHELF_ACTION_WINDOW_ACTIVATED;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc index ae700a0..7e3e70db 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -4146,9 +4146,12 @@ // Wait for real app icon image is decoded and set for shelf item. shelf_controller->GetLastItemImage(); - // Should have only one update that guarantees default icon was not set in + // Should have only one update for newly created window with no-icon set plus + // update for each scale factor. That guarantees default icon was not set in // between. - EXPECT_EQ(update_count_before_launch + 1, shelf_controller->updated_count()); + EXPECT_EQ( + update_count_before_launch + 1 + ui::GetSupportedScaleFactors().size(), + shelf_controller->updated_count()); } TEST_P(ChromeLauncherControllerArcDefaultAppsTest, PlayStoreDeferredLaunch) {
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index bdc5c42b..048b1ad 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -146,9 +146,8 @@ // to determine whether or not to offer save of Autofill data. However, we // don't allow saving of Autofill data while in incognito anyway, so an // incognito code path should never get far enough to query StrikeDatabase. - return profile->IsOffTheRecord() - ? nullptr - : StrikeDatabaseFactory::GetForProfile(profile); + DCHECK(!profile->IsOffTheRecord()); + return StrikeDatabaseFactory::GetForProfile(profile); } ukm::UkmRecorder* ChromeAutofillClient::GetUkmRecorder() {
diff --git a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc index 69e4ff44..96e59c91 100644 --- a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc +++ b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
@@ -5,14 +5,17 @@ #include "base/bind.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/bind_test_util.h" #include "base/timer/timer.h" #include "build/build_config.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/platform_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h" #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -29,14 +32,17 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "ui/base/dragdrop/os_exchange_data.h" +#include "ui/gfx/image/image_skia.h" using bookmarks::BookmarkModel; +using bookmarks::BookmarkNode; using bookmarks::UrlAndTitle; namespace { const char kPersistBookmarkURL[] = "http://www.cnn.com/"; const char kPersistBookmarkTitle[] = "CNN"; -} // namespace +} // namespace class TestBookmarkTabHelperObserver : public BookmarkTabHelperObserver { public: @@ -74,9 +80,8 @@ base::RepeatingTimer timer; timer.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(15), - base::Bind(&CheckAnimation, browser(), runner->QuitClosure())); + FROM_HERE, base::TimeDelta::FromMilliseconds(15), + base::BindRepeating(&CheckAnimation, browser(), runner->QuitClosure())); runner->Run(); return base::Time::Now() - start; } @@ -109,8 +114,7 @@ IN_PROC_BROWSER_TEST_F(BookmarkBrowsertest, PRE_Persist) { BookmarkModel* bookmark_model = WaitForBookmarkModel(browser()->profile()); - bookmarks::AddIfNotBookmarked(bookmark_model, - GURL(kPersistBookmarkURL), + bookmarks::AddIfNotBookmarked(bookmark_model, GURL(kPersistBookmarkURL), base::ASCIIToUTF16(kPersistBookmarkTitle)); } @@ -149,8 +153,7 @@ Browser* browser2 = observer.WaitForSingleNewBrowser(); BookmarkModel* bookmark_model2 = WaitForBookmarkModel(browser2->profile()); - bookmarks::AddIfNotBookmarked(bookmark_model1, - GURL(kPersistBookmarkURL), + bookmarks::AddIfNotBookmarked(bookmark_model1, GURL(kPersistBookmarkURL), base::ASCIIToUTF16(kPersistBookmarkTitle)); std::vector<UrlAndTitle> urls1, urls2; bookmark_model1->GetBookmarks(&urls1); @@ -164,10 +167,10 @@ // Flaky on Linux: http://crbug.com/504869. #if defined(OS_LINUX) #define MAYBE_HideStarOnNonbookmarkedInterstitial \ - DISABLED_HideStarOnNonbookmarkedInterstitial + DISABLED_HideStarOnNonbookmarkedInterstitial #else #define MAYBE_HideStarOnNonbookmarkedInterstitial \ - HideStarOnNonbookmarkedInterstitial + HideStarOnNonbookmarkedInterstitial #endif IN_PROC_BROWSER_TEST_F(BookmarkBrowsertest, MAYBE_HideStarOnNonbookmarkedInterstitial) { @@ -180,8 +183,7 @@ BookmarkModel* bookmark_model = WaitForBookmarkModel(browser()->profile()); GURL bookmark_url = embedded_test_server()->GetURL("example.test", "/"); - bookmarks::AddIfNotBookmarked(bookmark_model, - bookmark_url, + bookmarks::AddIfNotBookmarked(bookmark_model, bookmark_url, base::ASCIIToUTF16("Bookmark")); TestBookmarkTabHelperObserver bookmark_observer; @@ -207,3 +209,96 @@ tab_helper->RemoveObserver(&bookmark_observer); } + +// Provides coverage for the Bookmark Manager bookmark drag and drag image +// generation for dragging a single bookmark. +IN_PROC_BROWSER_TEST_F(BookmarkBrowsertest, DragSingleBookmark) { + BookmarkModel* model = WaitForBookmarkModel(browser()->profile()); + const base::string16 page_title(base::ASCIIToUTF16("foo")); + const GURL page_url("http://www.google.com"); + const BookmarkNode* root = model->bookmark_bar_node(); + const BookmarkNode* node = model->AddURL(root, 0, page_title, page_url); + + auto run_loop = std::make_unique<base::RunLoop>(); + + chrome::DoBookmarkDragCallback cb = base::BindLambdaForTesting( + [&run_loop, page_title, page_url]( + const ui::OSExchangeData& drag_data, gfx::NativeView native_view, + ui::DragDropTypes::DragEventSource source, int operation) { + GURL url; + base::string16 title; + EXPECT_TRUE(drag_data.provider().GetURLAndTitle( + ui::OSExchangeData::FilenameToURLPolicy::DO_NOT_CONVERT_FILENAMES, + &url, &title)); + EXPECT_EQ(page_url, url); + EXPECT_EQ(page_title, title); +#if !defined(OS_WIN) + // On Windows, GetDragImage() is a NOTREACHED() as the Windows + // implementation of OSExchangeData just sets the drag image on the OS + // API. + // See https://crbug.com/893388. + EXPECT_FALSE(drag_data.provider().GetDragImage().isNull()); +#endif + run_loop->Quit(); + }); + + constexpr int kDragNodeIndex = 0; + chrome::DragBookmarksForTest( + browser()->profile(), + {{node}, + kDragNodeIndex, + platform_util::GetViewForWindow(browser()->window()->GetNativeWindow()), + ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE}, + std::move(cb)); + + run_loop->Run(); +} + +// Provides coverage for the Bookmark Manager bookmark drag and drag image +// generation for dragging multiple bookmarks. +IN_PROC_BROWSER_TEST_F(BookmarkBrowsertest, DragMultipleBookmarks) { + BookmarkModel* model = WaitForBookmarkModel(browser()->profile()); + const base::string16 page_title(base::ASCIIToUTF16("foo")); + const GURL page_url("http://www.google.com"); + const BookmarkNode* root = model->bookmark_bar_node(); + const BookmarkNode* node1 = model->AddURL(root, 0, page_title, page_url); + const BookmarkNode* node2 = model->AddFolder(root, 0, page_title); + + auto run_loop = std::make_unique<base::RunLoop>(); + + chrome::DoBookmarkDragCallback cb = base::BindLambdaForTesting( + [&run_loop](const ui::OSExchangeData& drag_data, + gfx::NativeView native_view, + ui::DragDropTypes::DragEventSource source, int operation) { +#if !defined(OS_MACOSX) + GURL url; + base::string16 title; + // On Mac 10.11 and 10.12, this returns true, even though we set no url. + // See https://crbug.com/893432. + EXPECT_FALSE(drag_data.provider().GetURLAndTitle( + ui::OSExchangeData::FilenameToURLPolicy::DO_NOT_CONVERT_FILENAMES, + &url, &title)); +#endif +#if !defined(OS_WIN) + // On Windows, GetDragImage() is a NOTREACHED() as the Windows + // implementation of OSExchangeData just sets the drag image on the OS + // API. + // See https://crbug.com/893388. + EXPECT_FALSE(drag_data.provider().GetDragImage().isNull()); +#endif + run_loop->Quit(); + }); + + constexpr int kDragNodeIndex = 1; + chrome::DragBookmarksForTest(browser()->profile(), + { + {node1, node2}, + kDragNodeIndex, + platform_util::GetViewForWindow( + browser()->window()->GetNativeWindow()), + ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE, + }, + std::move(cb)); + + run_loop->Run(); +}
diff --git a/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc b/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc index e753432..1718324 100644 --- a/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc +++ b/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc
@@ -24,6 +24,17 @@ namespace chrome { +BookmarkDragParams::BookmarkDragParams( + std::vector<const bookmarks::BookmarkNode*> nodes, + int drag_node_index, + gfx::NativeView view, + ui::DragDropTypes::DragEventSource source) + : nodes(std::move(nodes)), + drag_node_index(drag_node_index), + view(view), + source(source) {} +BookmarkDragParams::~BookmarkDragParams() = default; + int DropBookmarks(Profile* profile, const BookmarkNodeData& data, const BookmarkNode* parent_node,
diff --git a/chrome/browser/ui/bookmarks/bookmark_drag_drop.h b/chrome/browser/ui/bookmarks/bookmark_drag_drop.h index 890d705d2..47b11c2 100644 --- a/chrome/browser/ui/bookmarks/bookmark_drag_drop.h +++ b/chrome/browser/ui/bookmarks/bookmark_drag_drop.h
@@ -18,13 +18,46 @@ struct BookmarkNodeData; } +namespace ui { +class OSExchangeData; +} + namespace chrome { +// Callback for implementing a system drag based on gathered bookmark drag data. +// Used in testing. +using DoBookmarkDragCallback = + base::OnceCallback<void(const ui::OSExchangeData& drag_data, + gfx::NativeView native_view, + ui::DragDropTypes::DragEventSource source, + int operation)>; + +struct BookmarkDragParams { + BookmarkDragParams(std::vector<const bookmarks::BookmarkNode*> nodes, + int drag_node_index, + gfx::NativeView view, + ui::DragDropTypes::DragEventSource source); + ~BookmarkDragParams(); + + // The bookmark nodes to be dragged. + std::vector<const bookmarks::BookmarkNode*> nodes; + + // The index of the main dragged node. + int drag_node_index; + + // The native view that initiated the drag. + gfx::NativeView view; + + // The source of the drag. + ui::DragDropTypes::DragEventSource source; +}; + // Starts the process of dragging a folder of bookmarks. -void DragBookmarks(Profile* profile, - const std::vector<const bookmarks::BookmarkNode*>& nodes, - gfx::NativeView view, - ui::DragDropTypes::DragEventSource source); +void DragBookmarks(Profile* profile, const BookmarkDragParams& params); + +void DragBookmarksForTest(Profile* profile, + const BookmarkDragParams& params, + DoBookmarkDragCallback do_drag_callback); // Drops the bookmark nodes that are in |data| onto |parent_node| at |index|. // |copy| indicates the source operation: if true then the bookmarks in |data|
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm index 711e219d..c81dbbf 100644 --- a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm +++ b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.mm
@@ -117,6 +117,7 @@ - (void)updateWebContents:(content::WebContents*)contents { [defaultTouchBar_ updateWebContents:contents]; + [webTextfieldTouchBar_ updateWebContents:contents]; [self invalidateTouchBar]; }
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h new file mode 100644 index 0000000..288fb93 --- /dev/null +++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h
@@ -0,0 +1,78 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_COCOA_TOUCHBAR_TEXT_SUGGESTIONS_TOUCH_BAR_CONTROLLER_H_ +#define CHROME_BROWSER_UI_COCOA_TOUCHBAR_TEXT_SUGGESTIONS_TOUCH_BAR_CONTROLLER_H_ + +#import <Cocoa/Cocoa.h> + +#include <memory> + +#import "base/mac/scoped_nsobject.h" +#include "chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h" +#import "ui/base/cocoa/touch_bar_forward_declarations.h" + +@class WebTextfieldTouchBarController; + +namespace content { +class WebContents; +} // namespace content + +namespace gfx { +class Range; +} // namespace gfx + +API_AVAILABLE(macos(10.12.2)) +@interface TextSuggestionsTouchBarController + : NSObject<NSTouchBarDelegate, NSCandidateListTouchBarItemDelegate> + +- (instancetype)initWithWebContents:(content::WebContents*)webContents + controller:(WebTextfieldTouchBarController*)controller; + +- (NSTouchBar*)makeTouchBar; + +- (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar + makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier; + +// Creates a NSCandidateListTouchBarItem that contains text suggestions +// based on the current text selection. +- (NSCandidateListTouchBarItem*)makeCandidateListItem; + +- (void)candidateListTouchBarItem:(NSCandidateListTouchBarItem*)anItem + endSelectingCandidateAtIndex:(NSInteger)index; + +- (void)updateTextSelection:(const base::string16&)text + range:(const gfx::Range&)range + offset:(size_t)offset; + +// Returns a range from start to the end of the word that the cursor is +// currently in. +- (NSRange)editingWordRangeFromText:(const base::string16&)text + cursorPosition:(size_t)cursor; + +- (void)requestSuggestions; + +// Select the range of the editing word and replace it with a suggestion +// from the touch bar. +- (void)replaceEditingWordWithSuggestion:(NSString*)text; + +@end + +@interface TextSuggestionsTouchBarController (ExposedForTesting) + +- (void)setWebContents:(content::WebContents*)webContents; +- (content::WebContents*)webContents; +- (void)setText:(NSString*)text; +- (NSString*)text; +- (void)setSelectionRange:(const gfx::Range&)range; +- (gfx::Range)selectionRange; +- (void)setSuggestions:(NSArray*)suggestions; +- (NSArray*)suggestions; +- (WebTextfieldTouchBarController*)controller; +- (void)setShouldIgnoreReplacementSelection:(BOOL)shouldIgnore; +- (void)setEditingWordRange:(const gfx::Range&)range offset:(size_t)offset; + +@end + +#endif // CHROME_BROWSER_UI_COCOA_TOUCHBAR_SUGGESTED_TEXT_TOUCH_BAR_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm new file mode 100644 index 0000000..7f3fb1b --- /dev/null +++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm
@@ -0,0 +1,322 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h" + +#include "base/i18n/break_iterator.h" +#include "base/strings/sys_string_conversions.h" +#include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" +#import "ui/base/cocoa/touch_bar_util.h" +#include "ui/gfx/range/range.h" + +namespace { +// Touch bar identifier. +NSString* const kTextSuggestionsTouchBarId = @"text-suggestions"; + +// Touch bar item identifiers. +NSString* const kTextSuggestionsItemsTouchId = @"TEXT-SUGGESTIONS-ITEMS"; +} // namespace + +namespace text_observer { +class API_AVAILABLE(macos(10.12.2)) WebContentsTextObserver + : public content::WebContentsObserver { + public: + WebContentsTextObserver(content::WebContents* web_contents, + TextSuggestionsTouchBarController* owner) + : WebContentsObserver(web_contents), owner_(owner) {} + + void UpdateWebContents(content::WebContents* web_contents) { + Observe(web_contents); + } + + void DidChangeTextSelection(const base::string16& text, + const gfx::Range& range, + size_t offset) override { + [owner_ updateTextSelection:text range:range offset:offset]; + } + + void DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url) override { + [owner_ updateTextSelection:base::string16() range:gfx::Range() offset:0]; + } + + private: + TextSuggestionsTouchBarController* owner_; // weak +}; +} // namespace text_observer + +@interface TextSuggestionsTouchBarController () { + // An observer for text selection changes. + std::unique_ptr<text_observer::WebContentsTextObserver> observer_; + + // The WebContents in which text is being selected and replaced. + content::WebContents* webContents_; // weak + + // The WebTextfieldTouchBarController that invalidates the touch bar. + WebTextfieldTouchBarController* controller_; // weak + + // The text on which suggestions are based. + base::scoped_nsobject<NSString> text_; + + // A list of NSTextCheckingResults containing text suggestions for |text_| at + // |selectionRange_|. + base::scoped_nsobject<NSArray> suggestions_; + + // The currently selected range. If the range has length = 0, it is simply a + // cursor position. + NSRange selectionRange_; + + // The range of the word that's currently being edited. Used when replacing + // the current editing word with a selected suggestion. If length = 0, there + // is no word currently being edited and the suggestion will be placed at the + // cursor. + NSRange editingWordRange_; + + // The location of |editingWordRange_| within the total text, which may be + // longer than the text received on text selection update. Used for checking + // when to ignore replacement text selections. + NSRange offsetEditingWordRange_; + + // When YES, -updateTextSelection:range: should ignore a text selection that + // is equal to the editing word range. Set to YES when + // -replaceEditingWordWithSuggestion: modifies the current text selection. + // Reset to NO when the text selection for replacing the editing word reaches + // -updateTextSelection:range:. + BOOL shouldIgnoreReplacementSelection_; +} +@end + +@implementation TextSuggestionsTouchBarController + +- (BOOL)isTextfieldFocused { + return webContents_ && webContents_->IsFocusedElementEditable(); +} + +- (instancetype)initWithWebContents:(content::WebContents*)webContents + controller: + (WebTextfieldTouchBarController*)controller { + if ((self = [super init])) { + webContents_ = webContents; + controller_ = controller; + observer_.reset( + new text_observer::WebContentsTextObserver(webContents_, self)); + shouldIgnoreReplacementSelection_ = NO; + } + + return self; +} + +- (NSTouchBar*)makeTouchBar { + if (![self isTextfieldFocused] || ![suggestions_ count]) + return nil; + + base::scoped_nsobject<NSTouchBar> touchBar([[ui::NSTouchBar() alloc] init]); + [touchBar + setCustomizationIdentifier:ui::GetTouchBarId(kTextSuggestionsTouchBarId)]; + [touchBar setDelegate:self]; + + [touchBar setDefaultItemIdentifiers:@[ kTextSuggestionsItemsTouchId ]]; + return touchBar.autorelease(); +} + +- (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar + makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { + if (![identifier hasSuffix:kTextSuggestionsItemsTouchId]) + return nil; + + return [self makeCandidateListItem]; +} + +- (NSCandidateListTouchBarItem*)makeCandidateListItem { + base::scoped_nsobject<NSCandidateListTouchBarItem> candidateListItem( + [[NSCandidateListTouchBarItem alloc] + initWithIdentifier:kTextSuggestionsItemsTouchId]); + + [candidateListItem setDelegate:self]; + if (selectionRange_.length) + [candidateListItem setCollapsed:YES]; + + [candidateListItem setCandidates:suggestions_ + forSelectedRange:selectionRange_ + inString:text_]; + + return candidateListItem.autorelease(); +} + +- (void)candidateListTouchBarItem:(NSCandidateListTouchBarItem*)anItem + endSelectingCandidateAtIndex:(NSInteger)index { + if (index == NSNotFound) + return; + + if (anItem) { + NSTextCheckingResult* selectedResult = anItem.candidates[index]; + [self replaceEditingWordWithSuggestion:[selectedResult replacementString]]; + } + + ui::LogTouchBarUMA(ui::TouchBarAction::TEXT_SUGGESTION); +} + +- (void)updateTextSelection:(const base::string16&)text + range:(const gfx::Range&)range + offset:(size_t)offset { + if (shouldIgnoreReplacementSelection_ && + range == gfx::Range(offsetEditingWordRange_)) { + shouldIgnoreReplacementSelection_ = NO; + return; + } + + if (![self isTextfieldFocused]) { + [controller_ invalidateTouchBar]; + return; + } + + // TODO(crbug.com/880642): It's possible for a range out of the text bounds + // to be passed in. Investigate this. + if (range.start() - offset > text.length() || + range.end() - offset > text.length()) { + text_.reset([[NSString alloc] init]); + selectionRange_ = NSMakeRange(0, 0); + editingWordRange_ = NSMakeRange(0, 0); + offsetEditingWordRange_ = NSMakeRange(0, 0); + return; + } + + text_.reset([base::SysUTF16ToNSString(text) retain]); + selectionRange_ = range.ToNSRange(); + selectionRange_.location -= offset; + + editingWordRange_ = [self editingWordRangeFromText:text + cursorPosition:selectionRange_.location]; + + offsetEditingWordRange_ = editingWordRange_; + offsetEditingWordRange_.location += offset; + [self requestSuggestions]; +} + +- (NSRange)editingWordRangeFromText:(const base::string16&)text + cursorPosition:(size_t)cursor { + // The cursor should not be off the end of the text. + DCHECK(cursor <= text.length()); + + // Default range is just the cursor position. This is used if BreakIterator + // cannot be initialized, there is no text in the textfield, or the cursor is + // at the front of a word. + size_t location = cursor; + size_t length = 0; + + base::i18n::BreakIterator iter(text, base::i18n::BreakIterator::BREAK_WORD); + + if (iter.Init()) { + // Repeat iter.Advance() until end of line is reached or + // current iterator position passes cursor position. + while (iter.pos() < cursor && iter.Advance()) { + } + + // If BreakIterator stopped at the end of a word, the cursor is in/at the + // end of a word so the editing word range is [word start, word end]. + if (iter.IsWord()) { + location = iter.prev(); + length = cursor - iter.prev(); + } + } + + return NSMakeRange(location, length); +} + +- (void)requestSuggestions { + NSSpellChecker* spell_checker = [NSSpellChecker sharedSpellChecker]; + [spell_checker + requestCandidatesForSelectedRange:selectionRange_ + inString:text_ + types:NSTextCheckingAllSystemTypes + options:nil + inSpellDocumentWithTag:0 + completionHandler:^( + NSInteger sequenceNumber, + NSArray<NSTextCheckingResult*>* candidates) { + dispatch_async(dispatch_get_main_queue(), ^{ + suggestions_.reset([candidates copy]); + [controller_ invalidateTouchBar]; + }); + }]; +} + +- (void)replaceEditingWordWithSuggestion:(NSString*)text { + // If the editing word is not selected in its entirety, modify the selection + // to cover the current editing word. + if (!NSEqualRanges(editingWordRange_, selectionRange_)) { + shouldIgnoreReplacementSelection_ = YES; + int start_adjust = editingWordRange_.location - selectionRange_.location; + int end_adjust = (editingWordRange_.location + editingWordRange_.length) - + (selectionRange_.location + selectionRange_.length); + webContents_->AdjustSelectionByCharacterOffset(start_adjust, end_adjust, + false); + } + webContents_->Replace(base::SysNSStringToUTF16(text)); +} + +- (void)setWebContents:(content::WebContents*)webContents { + webContents_ = webContents; + observer_->UpdateWebContents(webContents); + + if (![self isTextfieldFocused]) { + [controller_ invalidateTouchBar]; + return; + } + + const base::string16 text = + webContents_->GetTopLevelRenderWidgetHostView()->GetSurroundingText(); + const gfx::Range range = + webContents_->GetTopLevelRenderWidgetHostView()->GetSelectedRange(); + const size_t offset = webContents_->GetTopLevelRenderWidgetHostView() + ->GetOffsetForSurroundingText(); + + [self updateTextSelection:text range:range offset:offset]; +} + +- (content::WebContents*)webContents { + return webContents_; +} + +- (void)setText:(NSString*)text { + text_.reset([text copy]); +} + +- (NSString*)text { + return text_; +} + +- (void)setSelectionRange:(const gfx::Range&)range { + selectionRange_ = range.ToNSRange(); +} + +- (gfx::Range)selectionRange { + return gfx::Range(selectionRange_); +} + +- (void)setSuggestions:(NSArray*)suggestions { + suggestions_.reset([suggestions copy]); +} + +- (NSArray*)suggestions { + return suggestions_; +} + +- (WebTextfieldTouchBarController*)controller { + return controller_; +} + +- (void)setShouldIgnoreReplacementSelection:(BOOL)shouldIgnore { + shouldIgnoreReplacementSelection_ = shouldIgnore; +} + +- (void)setEditingWordRange:(const gfx::Range&)range offset:(size_t)offset { + editingWordRange_ = range.ToNSRange(); + offsetEditingWordRange_ = NSMakeRange(editingWordRange_.location + offset, + editingWordRange_.length); +} + +@end
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm new file mode 100644 index 0000000..bc5949f --- /dev/null +++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm
@@ -0,0 +1,327 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Cocoa/Cocoa.h> + +#include "base/mac/mac_util.h" +#include "base/mac/scoped_nsobject.h" +#include "base/strings/sys_string_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "build/build_config.h" +#include "chrome/browser/ui/browser.h" +#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" +#import "chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h" +#include "chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h" +#include "chrome/common/chrome_features.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" +#include "content/public/test/test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#import "ui/base/cocoa/touch_bar_util.h" + +API_AVAILABLE(macos(10.12.2)) +@interface MockWebTextfieldTouchBarController : WebTextfieldTouchBarController { + // Counter for the number of times invalidateTouchBar is called. + int numInvalidations_; +} +- (int)numInvalidations; + +- (void)resetNumInvalidations; + +@end + +@implementation MockWebTextfieldTouchBarController + +- (void)invalidateTouchBar { + numInvalidations_++; +} + +- (int)numInvalidations { + return numInvalidations_; +} + +- (void)resetNumInvalidations { + numInvalidations_ = 0; +} + +@end + +API_AVAILABLE(macos(10.12.2)) +@interface MockTextSuggestionsTouchBarController + : TextSuggestionsTouchBarController +- (NSString*)firstSuggestion; +@end + +@implementation MockTextSuggestionsTouchBarController + +- (void)requestSuggestions { + [self setSuggestions:@[ [self text] ]]; + [[self controller] invalidateTouchBar]; +} + +- (NSString*)firstSuggestion { + return [self suggestions][0]; +} + +@end + +namespace { + +class TextSuggestionsTouchBarControllerTest : public InProcessBrowserTest { + public: + void SetUp() override { + InProcessBrowserTest::SetUp(); + feature_list_.InitAndEnableFeature(features::kTextSuggestionsTouchBar); + } + + void SetUpOnMainThread() override { + if (@available(macOS 10.12.2, *)) { + web_textfield_controller_.reset( + [[MockWebTextfieldTouchBarController alloc] init]); + [web_textfield_controller_ resetNumInvalidations]; + touch_bar_controller_.reset([[MockTextSuggestionsTouchBarController alloc] + initWithWebContents:GetActiveWebContents() + controller:web_textfield_controller_]); + } + } + + void FocusTextfield() { + content::WindowedNotificationObserver focus_observer( + content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE, + content::NotificationService::AllSources()); + ui_test_utils::NavigateToURL( + browser(), + GURL("data:text/html;charset=utf-8,<input type=\"text\" autofocus>")); + focus_observer.Wait(); + } + + void UnfocusTextfield() { + ui_test_utils::NavigateToURL(browser(), GURL("about:blank")); + } + + content::WebContents* GetActiveWebContents() { + return browser()->tab_strip_model()->GetActiveWebContents(); + } + + API_AVAILABLE(macos(10.12.2)) + base::scoped_nsobject<MockWebTextfieldTouchBarController> + web_textfield_controller_; + + API_AVAILABLE(macos(10.12.2)) + base::scoped_nsobject<MockTextSuggestionsTouchBarController> + touch_bar_controller_; + base::test::ScopedFeatureList feature_list_; +}; + +// Tests to check if the touch bar shows up properly. +IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest, MakeTouchBar) { + if (@available(macOS 10.12.2, *)) { + NSString* const kTextSuggestionsTouchBarId = @"text-suggestions"; + NSArray* const kSuggestions = @[ @"text" ]; + + // Touch bar shouldn't appear if the focused element is not a textfield. + UnfocusTextfield(); + [touch_bar_controller_ setSuggestions:kSuggestions]; + EXPECT_FALSE([touch_bar_controller_ makeTouchBar]); + + // Touch bar shouldn't appear if there are no suggestions. + FocusTextfield(); + [touch_bar_controller_ setSuggestions:[NSArray array]]; + EXPECT_FALSE([touch_bar_controller_ makeTouchBar]); + + // Touch bar should appear if textfield is focused and there are + // suggestions. + [touch_bar_controller_ setSuggestions:kSuggestions]; + NSTouchBar* touch_bar = [touch_bar_controller_ makeTouchBar]; + EXPECT_TRUE(touch_bar); + EXPECT_TRUE([[touch_bar customizationIdentifier] + isEqual:ui::GetTouchBarId(kTextSuggestionsTouchBarId)]); + } +} + +// Tests that a change in text selection is handled properly. +IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest, + UpdateTextSelection) { + if (@available(macOS 10.12.2, *)) { + NSString* const kText = @"text"; + NSString* const kEmptyText = @""; + const gfx::Range kRange = gfx::Range(0, 4); + const gfx::Range kEmptyRange = gfx::Range(); + + // If not in a textfield, + // 1. Textfield text should not be saved. + // 2. Selected range should not be saved. + // 3. Touch bar should be invalidated (if on MacOS 10.12.2 or later). + UnfocusTextfield(); + [touch_bar_controller_ setText:kEmptyText]; + [touch_bar_controller_ setSelectionRange:kEmptyRange]; + [web_textfield_controller_ resetNumInvalidations]; + + [touch_bar_controller_ updateTextSelection:base::SysNSStringToUTF16(kText) + range:kRange + offset:0]; + EXPECT_STREQ(kEmptyText.UTF8String, + [touch_bar_controller_ text].UTF8String); + EXPECT_EQ(kEmptyRange, [touch_bar_controller_ selectionRange]); + EXPECT_EQ(1, [web_textfield_controller_ numInvalidations]); + + // If in a textfield and on MacOS 10.12.2 or later, + // 1. Textfield text should be saved. + // 2. Selected range should be saved. + // 3. Suggestions should be generated based on text selection. + // 4. Touch bar should be invalidated. + FocusTextfield(); + [touch_bar_controller_ setText:kEmptyText]; + [touch_bar_controller_ setSelectionRange:kEmptyRange]; + [web_textfield_controller_ resetNumInvalidations]; + + [touch_bar_controller_ updateTextSelection:base::SysNSStringToUTF16(kText) + range:kRange + offset:0]; + EXPECT_STREQ(kText.UTF8String, [touch_bar_controller_ text].UTF8String); + EXPECT_EQ(kRange, [touch_bar_controller_ selectionRange]); + EXPECT_STREQ(kText.UTF8String, + [touch_bar_controller_ firstSuggestion].UTF8String); + EXPECT_EQ(1, [web_textfield_controller_ numInvalidations]); + } +} + +// Tests that a range outside of the text bounds will set the selection range +// to empty. +IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest, + RangeOutOfTextBounds) { + if (@available(macOS 10.12.2, *)) { + FocusTextfield(); + [touch_bar_controller_ setText:@""]; + [touch_bar_controller_ setSelectionRange:gfx::Range()]; + + [touch_bar_controller_ + updateTextSelection:base::string16(base::ASCIIToUTF16("text")) + range:gfx::Range(4, 5) + offset:0]; + EXPECT_STREQ("", [touch_bar_controller_ text].UTF8String); + EXPECT_EQ(gfx::Range(), [touch_bar_controller_ selectionRange]); + + [touch_bar_controller_ + updateTextSelection:base::string16(base::ASCIIToUTF16("text")) + range:gfx::Range(2, 5) + offset:0]; + EXPECT_STREQ("", [touch_bar_controller_ text].UTF8String); + EXPECT_EQ(gfx::Range(), [touch_bar_controller_ selectionRange]); + } +} + +// Tests that a change in WebContents is handled properly. +IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest, SetWebContents) { + if (@available(macOS 10.12.2, *)) { + NSString* const kText = @"text"; + const gfx::Range kRange = gfx::Range(1, 1); + + FocusTextfield(); + + // A null-pointer should not break the controller. + [touch_bar_controller_ setWebContents:nullptr]; + EXPECT_FALSE([touch_bar_controller_ webContents]); + + [touch_bar_controller_ setText:kText]; + [touch_bar_controller_ setSelectionRange:kRange]; + + // The text selection should change on MacOS 10.12.2 and later if the + // WebContents pointer is not null. + [touch_bar_controller_ setWebContents:GetActiveWebContents()]; + EXPECT_EQ(GetActiveWebContents(), [touch_bar_controller_ webContents]); + EXPECT_STRNE(kText.UTF8String, [touch_bar_controller_ text].UTF8String); + EXPECT_NE(kRange, [touch_bar_controller_ selectionRange]); + } +} + +// Tests that the selection created when replacing the editing word with a +// suggestion is ignored. +IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest, + IgnoreReplacementSelection) { + if (@available(macOS 10.12.2, *)) { + NSString* const kText = @"text"; + const base::string16 kEmptyText = base::string16(); + const gfx::Range kRange = gfx::Range(0, 4); + const gfx::Range kEmptyRange = gfx::Range(); + + FocusTextfield(); + [touch_bar_controller_ setText:kText]; + [touch_bar_controller_ setSelectionRange:kRange]; + + // If ignoreReplacementSelection is YES and new selection range is equal to + // editing word range, ignore text selection update. + [touch_bar_controller_ setShouldIgnoreReplacementSelection:YES]; + [touch_bar_controller_ setEditingWordRange:kEmptyRange offset:0]; + [touch_bar_controller_ updateTextSelection:kEmptyText + range:kEmptyRange + offset:0]; + EXPECT_STREQ(kText.UTF8String, [touch_bar_controller_ text].UTF8String); + EXPECT_EQ(kRange, [touch_bar_controller_ selectionRange]); + + // If ignoreReplacementSelection is YES but new selection range is not equal + // to editing word range, do not ignore text selection update. + [touch_bar_controller_ setShouldIgnoreReplacementSelection:YES]; + [touch_bar_controller_ setEditingWordRange:kRange offset:0]; + [touch_bar_controller_ updateTextSelection:kEmptyText + range:kEmptyRange + offset:0]; + EXPECT_STREQ("", [touch_bar_controller_ text].UTF8String); + EXPECT_EQ(gfx::Range(), [touch_bar_controller_ selectionRange]); + + [touch_bar_controller_ setText:kText]; + [touch_bar_controller_ setSelectionRange:kRange]; + + // If ignoreReplacementSelection is NO and new selection range is equal to + // editing word range, do not ignore text selection update. + [touch_bar_controller_ setShouldIgnoreReplacementSelection:NO]; + [touch_bar_controller_ setEditingWordRange:kEmptyRange offset:0]; + [touch_bar_controller_ updateTextSelection:kEmptyText + range:kEmptyRange + offset:0]; + EXPECT_STREQ("", [touch_bar_controller_ text].UTF8String); + EXPECT_EQ(gfx::Range(), [touch_bar_controller_ selectionRange]); + } +} + +// Tests that offsets are properly handled. +IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest, Offset) { + if (@available(macOS 10.12.2, *)) { + const base::string16 kText = + base::string16(base::ASCIIToUTF16("hello world")); + const gfx::Range kRange = gfx::Range(3, 3); + const size_t kOffset = 1; + const gfx::Range kOffsetRange = + gfx::Range(kRange.start() - kOffset, kRange.end() - kOffset); + + FocusTextfield(); + [touch_bar_controller_ setSelectionRange:gfx::Range()]; + + // |selectionRange_| should include offset. + [touch_bar_controller_ updateTextSelection:kText + range:kRange + offset:kOffset]; + if (@available(macOS 10.12.2, *)) + EXPECT_EQ(kOffsetRange, [touch_bar_controller_ selectionRange]); + else + EXPECT_EQ(gfx::Range(), [touch_bar_controller_ selectionRange]); + + // The check for ignoring text selection updates should still work with + // offsets. + [touch_bar_controller_ setShouldIgnoreReplacementSelection:YES]; + [touch_bar_controller_ updateTextSelection:kText + range:gfx::Range(1, 7) + offset:kOffset]; + if (@available(macOS 10.12.2, *)) + EXPECT_EQ(gfx::Range(0, 6), [touch_bar_controller_ selectionRange]); + else + EXPECT_EQ(gfx::Range(), [touch_bar_controller_ selectionRange]); + } +} + +} // namespace
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm new file mode 100644 index 0000000..feb982f --- /dev/null +++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm
@@ -0,0 +1,155 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Cocoa/Cocoa.h> + +#include "base/strings/utf_string_conversions.h" +#include "base/test/metrics/histogram_tester.h" +#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" +#import "chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h" +#include "testing/gtest/include/gtest/gtest.h" +#import "ui/base/cocoa/touch_bar_util.h" +#include "ui/gfx/range/range.h" + +const base::string16 kEmptyText(base::ASCIIToUTF16("")); +const base::string16 kWord(base::ASCIIToUTF16("hello")); +const base::string16 kWordWithTrailingWhitespace(base::ASCIIToUTF16("hello ")); +const base::string16 kWordWithLeadingWhitespace(base::ASCIIToUTF16(" hello")); +const base::string16 kMultipleWords(base::ASCIIToUTF16("hello world")); +const base::string16 kWhitespace(base::ASCIIToUTF16(" ")); + +class TextSuggestionsTouchBarControllerTest : public CocoaTest { + public: + void SetUp() override { + CocoaTest::SetUp(); + if (@available(macOS 10.12.2, *)) + controller_.reset([[TextSuggestionsTouchBarController alloc] init]); + } + + gfx::Range GetEditingWordRange(const base::string16& text, size_t cursor) + API_AVAILABLE(macos(10.12.2)) { + NSRange range = + [controller_.get() editingWordRangeFromText:text cursorPosition:cursor]; + return gfx::Range(range); + } + + API_AVAILABLE(macos(10.12.2)) + base::scoped_nsobject<TextSuggestionsTouchBarController> controller_; +}; + +// Tests that the NSCandidateListTouchBarItem collapses properly. +TEST_F(TextSuggestionsTouchBarControllerTest, CollapsedCandidateList) { + if (@available(macOS 10.12.2, *)) { + [controller_ setSelectionRange:gfx::Range()]; + EXPECT_FALSE([[controller_ makeCandidateListItem] isCollapsed]); + + [controller_ setSelectionRange:gfx::Range(0, 1)]; + EXPECT_TRUE([[controller_ makeCandidateListItem] isCollapsed]); + } +} + +// Tests that the editing word range is simply the cursor position if there +// is no text. +TEST_F(TextSuggestionsTouchBarControllerTest, EmptyTextEditingWordRange) { + if (@available(macOS 10.12.2, *)) + EXPECT_EQ(gfx::Range(0, 0), GetEditingWordRange(kEmptyText, 0)); +} + +// Tests that the editing word range contains the full word as the cursor +// moves through a word without breaks. +TEST_F(TextSuggestionsTouchBarControllerTest, WordEditingWordRange) { + if (@available(macOS 10.12.2, *)) { + EXPECT_EQ(gfx::Range(0, 0), GetEditingWordRange(kWord, 0)); + EXPECT_EQ(gfx::Range(0, 1), GetEditingWordRange(kWord, 1)); + EXPECT_EQ(gfx::Range(0, 2), GetEditingWordRange(kWord, 2)); + EXPECT_EQ(gfx::Range(0, 3), GetEditingWordRange(kWord, 3)); + EXPECT_EQ(gfx::Range(0, 4), GetEditingWordRange(kWord, 4)); + } +} + +// Tests that the editing word range is properly calculated as the cursor moves +// through non-word characters. +TEST_F(TextSuggestionsTouchBarControllerTest, WhitespaceEditingWordRange) { + if (@available(macOS 10.12.2, *)) { + EXPECT_EQ(gfx::Range(0, 0), GetEditingWordRange(kWhitespace, 0)); + EXPECT_EQ(gfx::Range(1, 1), GetEditingWordRange(kWhitespace, 1)); + EXPECT_EQ(gfx::Range(2, 2), GetEditingWordRange(kWhitespace, 2)); + EXPECT_EQ(gfx::Range(3, 3), GetEditingWordRange(kWhitespace, 3)); + EXPECT_EQ(gfx::Range(4, 4), GetEditingWordRange(kWhitespace, 4)); + EXPECT_EQ(gfx::Range(5, 5), GetEditingWordRange(kWhitespace, 5)); + } +} + +// Tests that the editing word range changes properly as the cursor moves +// from word to non-word characters. +TEST_F(TextSuggestionsTouchBarControllerTest, + TrailingWhitespaceEditingWordRange) { + if (@available(macOS 10.12.2, *)) { + EXPECT_EQ(gfx::Range(0, 0), + GetEditingWordRange(kWordWithTrailingWhitespace, 0)); + EXPECT_EQ(gfx::Range(0, 1), + GetEditingWordRange(kWordWithTrailingWhitespace, 1)); + EXPECT_EQ(gfx::Range(0, 2), + GetEditingWordRange(kWordWithTrailingWhitespace, 2)); + EXPECT_EQ(gfx::Range(0, 3), + GetEditingWordRange(kWordWithTrailingWhitespace, 3)); + EXPECT_EQ(gfx::Range(0, 4), + GetEditingWordRange(kWordWithTrailingWhitespace, 4)); + EXPECT_EQ(gfx::Range(0, 5), + GetEditingWordRange(kWordWithTrailingWhitespace, 5)); + EXPECT_EQ(gfx::Range(6, 6), + GetEditingWordRange(kWordWithTrailingWhitespace, 6)); + } +} + +// Tests that the editing word range changes properly as the cursor moves +// from non-word to word characters. +TEST_F(TextSuggestionsTouchBarControllerTest, + LeadingWhitespaceEditingWordRange) { + if (@available(macOS 10.12.2, *)) { + EXPECT_EQ(gfx::Range(0, 0), + GetEditingWordRange(kWordWithLeadingWhitespace, 0)); + EXPECT_EQ(gfx::Range(1, 1), + GetEditingWordRange(kWordWithLeadingWhitespace, 1)); + EXPECT_EQ(gfx::Range(1, 2), + GetEditingWordRange(kWordWithLeadingWhitespace, 2)); + EXPECT_EQ(gfx::Range(1, 3), + GetEditingWordRange(kWordWithLeadingWhitespace, 3)); + EXPECT_EQ(gfx::Range(1, 4), + GetEditingWordRange(kWordWithLeadingWhitespace, 4)); + EXPECT_EQ(gfx::Range(1, 5), + GetEditingWordRange(kWordWithLeadingWhitespace, 5)); + EXPECT_EQ(gfx::Range(1, 6), + GetEditingWordRange(kWordWithLeadingWhitespace, 6)); + } +} + +// Tests that the editing word range is properly calculated as the cursor moves +// from word to non-word and back to word characters. +TEST_F(TextSuggestionsTouchBarControllerTest, MultipleWordsEditingWordRange) { + if (@available(macOS 10.12.2, *)) { + EXPECT_EQ(gfx::Range(0, 0), GetEditingWordRange(kMultipleWords, 0)); + EXPECT_EQ(gfx::Range(0, 1), GetEditingWordRange(kMultipleWords, 1)); + EXPECT_EQ(gfx::Range(0, 2), GetEditingWordRange(kMultipleWords, 2)); + EXPECT_EQ(gfx::Range(0, 3), GetEditingWordRange(kMultipleWords, 3)); + EXPECT_EQ(gfx::Range(0, 4), GetEditingWordRange(kMultipleWords, 4)); + EXPECT_EQ(gfx::Range(0, 5), GetEditingWordRange(kMultipleWords, 5)); + EXPECT_EQ(gfx::Range(6, 6), GetEditingWordRange(kMultipleWords, 6)); + EXPECT_EQ(gfx::Range(6, 7), GetEditingWordRange(kMultipleWords, 7)); + EXPECT_EQ(gfx::Range(6, 8), GetEditingWordRange(kMultipleWords, 8)); + EXPECT_EQ(gfx::Range(6, 9), GetEditingWordRange(kMultipleWords, 9)); + EXPECT_EQ(gfx::Range(6, 10), GetEditingWordRange(kMultipleWords, 10)); + EXPECT_EQ(gfx::Range(6, 11), GetEditingWordRange(kMultipleWords, 11)); + } +} + +// Tests that touch bar usage is properly logged. +TEST_F(TextSuggestionsTouchBarControllerTest, TouchBarMetrics) { + if (@available(macOS 10.12.2, *)) { + base::HistogramTester histogram_tester; + [controller_ candidateListTouchBarItem:nil endSelectingCandidateAtIndex:1]; + histogram_tester.ExpectBucketCount("TouchBar.Default.Metrics", + ui::TouchBarAction::TEXT_SUGGESTION, 1); + } +}
diff --git a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h index d5fb4be6..622cd75 100644 --- a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h +++ b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h
@@ -14,6 +14,7 @@ @class BrowserWindowTouchBarController; @class CreditCardAutofillTouchBarController; +@class TextSuggestionsTouchBarController; @class TabContentsController; namespace autofill { @@ -31,6 +32,8 @@ BrowserWindowTouchBarController* controller_; // weak. base::scoped_nsobject<CreditCardAutofillTouchBarController> autofillTouchBarController_; + base::scoped_nsobject<TextSuggestionsTouchBarController> + textSuggestionsTouchBarController_; } + (WebTextfieldTouchBarController*)controllerForWindow:(NSWindow*)window; @@ -43,6 +46,8 @@ - (void)hideCreditCardAutofillTouchBar; +- (void)updateWebContents:(content::WebContents*)contents; + - (void)invalidateTouchBar; // Creates and returns a touch bar.
diff --git a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm index b8f98d68..76a9101 100644 --- a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm +++ b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm
@@ -12,10 +12,13 @@ #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" #import "chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h" #import "chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.h" +#import "chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h" #include "chrome/browser/ui/views/frame/browser_frame_mac.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/common/chrome_features.h" #include "content/public/browser/web_contents.h" #import "ui/base/cocoa/touch_bar_util.h" +#include "ui/base/ui_base_features.h" @implementation WebTextfieldTouchBarController @@ -34,6 +37,14 @@ (BrowserWindowTouchBarController*)controller { if ((self = [super init])) { controller_ = controller; + + if (base::FeatureList::IsEnabled(features::kTextSuggestionsTouchBar) || + base::FeatureList::IsEnabled(features::kExperimentalUi)) { + textSuggestionsTouchBarController_.reset( + [[TextSuggestionsTouchBarController alloc] + initWithWebContents:[controller_ webContents] + controller:self]); + } } return self; @@ -57,6 +68,10 @@ [self invalidateTouchBar]; } +- (void)updateWebContents:(content::WebContents*)contents { + [textSuggestionsTouchBarController_ setWebContents:contents]; +} + - (void)invalidateTouchBar { [controller_ invalidateTouchBar]; } @@ -64,6 +79,10 @@ - (NSTouchBar*)makeTouchBar { if (autofillTouchBarController_) return [autofillTouchBarController_ makeTouchBar]; + + if (textSuggestionsTouchBarController_) + return [textSuggestionsTouchBarController_ makeTouchBar]; + return nil; }
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc index 89b0fda..2ef6d8f 100644 --- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc +++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -238,8 +238,6 @@ return model->IsEnabledAt(index) ? kEnabled : kDisabled; } -} // namespace - class TestAppBannerManagerDesktop : public banners::AppBannerManagerDesktop { public: explicit TestAppBannerManagerDesktop(WebContents* web_contents) @@ -296,6 +294,8 @@ DISALLOW_COPY_AND_ASSIGN(TestAppBannerManagerDesktop); }; +} // namespace + // Parameters are {app_type, desktop_pwa_flag}. |app_type| controls whether it // is a Hosted or Bookmark app. |desktop_pwa_flag| enables the // kDesktopPWAWindowing flag. @@ -401,6 +401,8 @@ WebApplicationInfo web_app_info; web_app_info.app_url = app_url; web_app_info.scope = app_url.GetWithoutFilename(); + web_app_info.open_as_window = true; + app_ = InstallBookmarkApp(web_app_info); ui_test_utils::UrlLoadObserver url_observer( @@ -873,6 +875,64 @@ EXPECT_FALSE(model->IsEnabledAt(index)); } +// Tests that desktop PWAs open links in the browser. +IN_PROC_BROWSER_TEST_P(HostedAppPWAOnlyTest, + DesktopPWAsOpenLinksInAppWhenFeatureEnabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kDesktopPWAsStayInWindow); + + ASSERT_TRUE(https_server()->Start()); + ASSERT_TRUE(embedded_test_server()->Start()); + + InstallSecurePWA(); + ASSERT_TRUE(base::FeatureList::IsEnabled(features::kDesktopPWAsStayInWindow)); + ASSERT_TRUE( + extensions::util::GetInstalledPwaForUrl(profile(), GetSecureAppURL())); + + NavigateToURLAndWait(app_browser_, GetSecureAppURL()); + + ASSERT_TRUE(app_browser_->hosted_app_controller()); + + NavigateAndCheckForLocationBar(app_browser_, GURL(kExampleURL), true); +} + +// Tests that desktop PWAs open links in the browser. +IN_PROC_BROWSER_TEST_P(HostedAppPWAOnlyTest, + DesktopPWAsOpenLinksInBrowserWhenFeatureDisabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(features::kDesktopPWAsStayInWindow); + + ASSERT_TRUE(https_server()->Start()); + ASSERT_TRUE(embedded_test_server()->Start()); + + InstallSecurePWA(); + ASSERT_FALSE( + base::FeatureList::IsEnabled(features::kDesktopPWAsStayInWindow)); + ASSERT_TRUE( + extensions::util::GetInstalledPwaForUrl(profile(), GetSecureAppURL())); + + NavigateToURLAndWait(app_browser_, GetSecureAppURL()); + + ASSERT_TRUE(app_browser_->hosted_app_controller()); + + TestAppActionOpensForegroundTab( + base::BindOnce( + [](Browser* browser, content::WebContents* app_contents, + const GURL& target_url) { + content::TestNavigationObserver observer(target_url); + observer.StartWatchingNewWebContents(); + + std::string script = base::StringPrintf("window.location = '%s';", + target_url.spec().c_str()); + ASSERT_TRUE(content::ExecuteScript(app_contents, script)); + + observer.WaitForNavigationFinished(); + }, + app_browser_, app_browser_->tab_strip_model()->GetActiveWebContents(), + GURL(kExampleURL)), + GURL(kExampleURL)); +} + // Tests that PWA menus have an uninstall option. IN_PROC_BROWSER_TEST_P(HostedAppPWAOnlyTest, UninstallMenuOption) { ASSERT_TRUE(https_server()->Start());
diff --git a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc index e16693e..730e43c 100644 --- a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc +++ b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc
@@ -37,7 +37,6 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/geometry/rect_conversions.h" -#include "ui/gfx/range/range.h" #include "ui/gfx/text_utils.h" #if defined(OS_ANDROID)
diff --git a/chrome/browser/ui/startup/invalid_user_data_dir_interactive_uitest.cc b/chrome/browser/ui/startup/invalid_user_data_dir_interactive_uitest.cc new file mode 100644 index 0000000..cc39011 --- /dev/null +++ b/chrome/browser/ui/startup/invalid_user_data_dir_interactive_uitest.cc
@@ -0,0 +1,37 @@ +// 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/macros.h" +#include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/simple_message_box_internal.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/test/base/in_process_browser_test.h" + +// https://crbug.com/833624 +class InvalidUserDataDirTest : public InProcessBrowserTest { + public: + InvalidUserDataDirTest() {} + ~InvalidUserDataDirTest() override {} + + private: + void SetUp() override { + // Skip showing the error message box to avoid freezing the main thread. + chrome::internal::g_should_skip_message_box_for_test = true; + chrome::SetInvalidSpecifiedUserDataDir( + base::FilePath(FILE_PATH_LITERAL("foo/bar/baz"))); + InProcessBrowserTest::SetUp(); + } + + // This override makes sure the screen instance is not set because in normal + // browser initialization, the screen is not set until after the call to + // chrome::GetInvalidSpecifiedUserDataDir. + void SetScreenInstance() override {} + + DISALLOW_COPY_AND_ASSIGN(InvalidUserDataDirTest); +}; + +IN_PROC_BROWSER_TEST_F(InvalidUserDataDirTest, Basic) { + // A message dialog may be showing which would block shutdown. + chrome::Exit(); +}
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc b/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc index 033db6e3..f206f80 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc
@@ -5,16 +5,36 @@ #include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h" #include "base/message_loop/message_loop_current.h" +#include "base/no_destructor.h" +#include "base/strings/string_number_conversions.h" +#include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/bookmarks/bookmark_utils.h" #include "chrome/browser/ui/views_mode_controller.h" +#include "chrome/grit/platform_locale_settings.h" +#include "components/bookmarks/browser/base_bookmark_model_observer.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/browser/bookmark_node_data.h" #include "components/bookmarks/browser/bookmark_utils.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/os_exchange_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/font.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/image/canvas_image_source.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/render_text.h" +#include "ui/resources/grit/ui_resources.h" #include "ui/views/drag_utils.h" +#include "ui/views/style/platform_style.h" +#include "ui/views/style/typography.h" +#include "ui/views/style/typography_provider.h" #include "ui/views/widget/widget.h" using bookmarks::BookmarkModel; @@ -22,34 +42,277 @@ namespace chrome { -void DragBookmarks(Profile* profile, - const std::vector<const BookmarkNode*>& nodes, - gfx::NativeView view, - ui::DragDropTypes::DragEventSource source) { - DCHECK(!nodes.empty()); +namespace { - // Set up our OLE machinery. - ui::OSExchangeData data; - bookmarks::BookmarkNodeData drag_data(nodes); - drag_data.Write(profile->GetPath(), &data); +class BookmarkDragHelper; +// Generates a bookmark drag and drop chip image. +class BookmarkDragImageSource : public gfx::CanvasImageSource { + public: + // These DIP measurements come from the MD Bookmarks Drag Drop spec. + static constexpr int kContainerWidth = 172; + static constexpr int kContainerHeight = 40; + static constexpr int kContainerRadius = kContainerHeight / 2; + static constexpr SkColor kContainerColor = gfx::kGoogleBlue500; + + static constexpr int kIconContainerRadius = 12; + static constexpr int kIconSize = 16; + static constexpr SkColor kIconContainerColor = SK_ColorWHITE; + + static constexpr int kTitlePadding = 12; + + static constexpr int kCountPadding = 5; + static constexpr int kCountContainerRadius = 12; + static constexpr SkColor kCountContainerColor = gfx::kGoogleRed500; + + static constexpr gfx::Size kBookmarkDragImageSize = + gfx::Size(kContainerWidth, kContainerHeight + kCountContainerRadius); + + static constexpr int kDragImageOffsetX = kContainerWidth / 2; + static constexpr int kDragImageOffsetY = 0.9 * kContainerHeight; + + BookmarkDragImageSource(const base::string16& title, + const gfx::ImageSkia& icon, + size_t count) + : gfx::CanvasImageSource(kBookmarkDragImageSize, false), + title_(title), + icon_(icon), + count_(count) {} + + private: + // gfx::CanvasImageSource overrides: + void Draw(gfx::Canvas* canvas) override { + cc::PaintFlags paint_flags; + paint_flags.setAntiAlias(true); + + // Draw background. + gfx::RectF container_rect(0, kCountContainerRadius, kContainerWidth, + kContainerHeight); + paint_flags.setColor(kContainerColor); + canvas->DrawRoundRect(container_rect, kContainerRadius, paint_flags); + + // Draw icon container. + paint_flags.setColor(kIconContainerColor); + canvas->DrawCircle( + gfx::PointF(kContainerRadius, kContainerRadius + kCountContainerRadius), + kIconContainerRadius, paint_flags); + + // Draw icon image. + canvas->DrawImageInt( + icon_, kContainerRadius - kIconSize / 2, + kContainerRadius + kIconContainerRadius - kIconSize / 2); + + // Draw bookmark title. + gfx::FontList font_list = views::style::GetFont( + views::style::CONTEXT_LABEL, views::style::STYLE_PRIMARY); + gfx::Rect text_rect(kBookmarkDragImageSize); + text_rect.Inset(kContainerRadius + kIconContainerRadius + kTitlePadding, + kCountContainerRadius, + kContainerRadius - kIconContainerRadius, 0); + canvas->DrawStringRectWithFlags(title_, font_list, SK_ColorWHITE, text_rect, + gfx::Canvas::TEXT_ALIGN_LEFT); + + if (count_ <= 1) + return; + + // Draw bookmark count if more than 1 bookmark is dragged. + base::string16 count = base::NumberToString16(count_); + auto render_text = gfx::RenderText::CreateFor(gfx::Typesetter::BROWSER); + render_text->SetFontList(font_list); + render_text->SetCursorEnabled(false); + render_text->SetColor(SK_ColorWHITE); + render_text->SetText(count); + render_text->SetHorizontalAlignment(gfx::ALIGN_CENTER); + + // We measure the count text size to determine container width, as the + // container is a rounded rect behind the text. + int count_width = render_text->GetStringSize().width(); + int count_container_width = + std::max(kCountContainerRadius * 2, count_width + 2 * kCountPadding); + + // Draw the count container. + gfx::Rect count_container_rect( + container_rect.right() - count_container_width, 0, + count_container_width, kCountContainerRadius * 2); + paint_flags.setColor(kCountContainerColor); + canvas->DrawRoundRect(gfx::RectF(count_container_rect), + kCountContainerRadius, paint_flags); + + // Draw the count text. + render_text->SetDisplayRect(count_container_rect); + render_text->Draw(canvas); + } + + const base::string16 title_; + const gfx::ImageSkia icon_; + const int count_; +}; + +constexpr gfx::Size BookmarkDragImageSource::kBookmarkDragImageSize; + +// Helper class that takes a drag request, loads the icon from the bookmark +// model and then launches a system drag with a generated drag image. +// Owns itself. +class BookmarkDragHelper : public bookmarks::BaseBookmarkModelObserver { + public: + static base::WeakPtr<BookmarkDragHelper> Create( + Profile* profile, + const BookmarkDragParams& params, + DoBookmarkDragCallback do_drag_callback) { + base::WeakPtr<BookmarkDragHelper> ptr = + (new BookmarkDragHelper(profile, params, std::move(do_drag_callback))) + ->GetWeakPtr(); + ptr->Start(params.nodes.at(params.drag_node_index)); + return ptr; + } + + private: + BookmarkDragHelper(Profile* profile, + const BookmarkDragParams& params, + DoBookmarkDragCallback do_drag_callback) + : model_(BookmarkModelFactory::GetForBrowserContext(profile)), + count_(params.nodes.size()), + native_view_(params.view), + source_(params.source), + do_drag_callback_(std::move(do_drag_callback)), + observer_(this), + weak_factory_(this) { + observer_.Add(model_); + + // Set up our OLE machinery. + bookmarks::BookmarkNodeData bookmark_drag_data(params.nodes); + bookmark_drag_data.Write(profile->GetPath(), &drag_data_); + + operation_ = ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK; + if (bookmarks::CanAllBeEditedByUser(model_->client(), params.nodes)) + operation_ |= ui::DragDropTypes::DRAG_MOVE; + } + + void Start(const BookmarkNode* drag_node) { + drag_node_id_ = drag_node->id(); + + gfx::ImageSkia icon; + if (drag_node->is_url()) { + const gfx::Image& image = model_->GetFavicon(drag_node); + // If favicon is not loaded, the above call will initiate loading, and + // drag will proceed in BookmarkNodeFaviconChanged(). In rare cases, + // BookmarkNodeFaviconChanged() will never be called (e.g unfortunate + // bookmark deletion timing) and we intentionally leak at most one request + // in these cases which will clean up next drag. + if (!drag_node->is_favicon_loaded()) + return; + + icon = image.AsImageSkia(); + } else { + icon = GetBookmarkFolderIcon( + ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor( + ui::NativeTheme::kColorId_LabelEnabledColor)); + } + + OnBookmarkIconLoaded(drag_node, icon); + } + + void OnBookmarkIconLoaded(const BookmarkNode* drag_node, + const gfx::ImageSkia& icon) { + gfx::ImageSkia drag_image( + std::make_unique<BookmarkDragImageSource>( + drag_node->GetTitle(), + icon.isNull() + ? *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( + IDR_DEFAULT_FAVICON) + : icon, + count_), + BookmarkDragImageSource::kBookmarkDragImageSize); + + drag_data_.provider().SetDragImage( + drag_image, gfx::Vector2d(BookmarkDragImageSource::kDragImageOffsetX, + BookmarkDragImageSource::kDragImageOffsetY)); + + std::move(do_drag_callback_) + .Run(drag_data_, native_view_, source_, operation_); + + delete this; + } + + base::WeakPtr<BookmarkDragHelper> GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + + // bookmarks::BaseBookmarkModelObserver overrides: + void BookmarkModelChanged() override {} + + void BookmarkModelBeingDeleted(BookmarkModel* model) override { delete this; } + + void BookmarkNodeFaviconChanged(BookmarkModel* model, + const BookmarkNode* node) override { + if (node->id() != drag_node_id_) + return; + + const gfx::Image& image = model_->GetFavicon(node); + DCHECK(node->is_favicon_loaded()); + + OnBookmarkIconLoaded(node, image.AsImageSkia()); + } + + BookmarkModel* model_; + + int64_t drag_node_id_ = -1; + int count_; + gfx::NativeView native_view_; + ui::DragDropTypes::DragEventSource source_; + int operation_; + + DoBookmarkDragCallback do_drag_callback_; + + ui::OSExchangeData drag_data_; + + ScopedObserver<bookmarks::BookmarkModel, bookmarks::BookmarkModelObserver> + observer_; + + base::WeakPtrFactory<BookmarkDragHelper> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(BookmarkDragHelper); +}; + +void DoDragImpl(const ui::OSExchangeData& drag_data, + gfx::NativeView native_view, + ui::DragDropTypes::DragEventSource source, + int operation) { // Allow nested run loop so we get DnD events as we drag this around. base::MessageLoopCurrent::ScopedNestableTaskAllower nestable_task_allower; - int operation = ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK; - BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile); - if (bookmarks::CanAllBeEditedByUser(model->client(), nodes)) - operation |= ui::DragDropTypes::DRAG_MOVE; + views::Widget* widget = views::Widget::GetWidgetForNativeView(native_view); + DCHECK(widget); + widget->RunShellDrag(nullptr, drag_data, gfx::Point(), operation, source); +} - views::Widget* widget = views::Widget::GetWidgetForNativeView(view); +void DragBookmarksImpl(Profile* profile, + const BookmarkDragParams& params, + DoBookmarkDragCallback do_drag_callback) { + DCHECK(!params.nodes.empty()); + static base::NoDestructor<base::WeakPtr<BookmarkDragHelper>> g_drag_helper; + if (*g_drag_helper) + delete g_drag_helper->get(); - if (widget) { - widget->RunShellDrag(NULL, data, gfx::Point(), operation, source); - } else { - // We hit this case when we're using WebContentsViewWin or - // WebContentsViewAura, instead of WebContentsViewViews. - views::RunShellDrag(view, data, gfx::Point(), operation, source); - } + DCHECK(!*g_drag_helper); + + // Cleaned up in + // BookmarkDragHelper::BookmarkIconLoaded()/BookmarkModelBeingDeleted(), or + // above when a new drag is initiated before the favicon loads. + *g_drag_helper = + BookmarkDragHelper::Create(profile, params, std::move(do_drag_callback)); +} + +} // namespace + +void DragBookmarks(Profile* profile, const BookmarkDragParams& params) { + DragBookmarksImpl(profile, params, base::BindOnce(&DoDragImpl)); +} + +void DragBookmarksForTest(Profile* profile, + const BookmarkDragParams& params, + DoBookmarkDragCallback do_drag_callback) { + DragBookmarksImpl(profile, params, std::move(do_drag_callback)); } } // namespace chrome
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc index 0ac480b..621e3fed 100644 --- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc +++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
@@ -74,20 +74,17 @@ #if defined(USE_AURA) wm_state_.reset(new wm::WMState); #endif + + // TODO(pkasting): Try to move ViewsDelegate creation here as well; + // see https://crbug.com/691894#c1 + if (!views::LayoutProvider::Get()) + layout_provider_ = ChromeLayoutProvider::CreateLayoutProvider(); } void ChromeBrowserMainExtraPartsViews::PreCreateThreads() { #if defined(USE_AURA) views::InstallDesktopScreenIfNecessary(); #endif - - // TODO(pkasting): Try to move ViewsDelegate creation here as well; - // see https://crbug.com/691894#c1 - // The layout_provider_ must be intialized here instead of in - // ToolkitInitialized() because it relies on - // ui::MaterialDesignController::Intialize() having already been called. - if (!views::LayoutProvider::Get()) - layout_provider_ = ChromeLayoutProvider::CreateLayoutProvider(); } void ChromeBrowserMainExtraPartsViews::PreProfileInit() {
diff --git a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc index f72498d..994f889 100644 --- a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc +++ b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
@@ -43,9 +43,13 @@ BrowserView::GetBrowserViewForNativeWindow(window); if (!browser_view) return nullptr; - ToolbarActionView* reference_view = browser_view->toolbar_button_provider() - ->GetBrowserActionsContainer() - ->GetViewForId(extension_id); + DCHECK(browser_view->toolbar_button_provider()); + BrowserActionsContainer* const browser_actions_container = + browser_view->toolbar_button_provider()->GetBrowserActionsContainer(); + if (!browser_actions_container) + return nullptr; + ToolbarActionView* const reference_view = + browser_actions_container->GetViewForId(extension_id); return reference_view && reference_view->visible() ? reference_view : nullptr; }
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc index 74b1b2c..9d75af83 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -681,7 +681,11 @@ https_server_.AddDefaultHandlers(base::FilePath(kDocRoot)); ASSERT_TRUE(https_server_.Start()); ASSERT_TRUE(embedded_test_server()->Start()); + } + // |SetUpHostedApp()| must be called after |SetUpOnMainThread()| to make sure + // the Network Service process has been setup properly. + void SetUpHostedApp() { WebApplicationInfo web_app_info; web_app_info.app_url = GetAppURL(); web_app_info.scope = GetAppURL().GetWithoutFilename(); @@ -774,6 +778,7 @@ // bubble anchor adjustment (see |BubbleDialogDelegateView::CreateBubble()|). IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, PageInfoBubblePosition) { + SetUpHostedApp(); // Resize app window to only take up the left half of the screen. views::Widget* widget = browser_view_->GetWidget(); gfx::Size screen_size = @@ -796,6 +801,7 @@ } IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, FocusableViews) { + SetUpHostedApp(); EXPECT_TRUE(browser_view_->contents_web_view()->HasFocus()); browser_view_->GetFocusManager()->AdvanceFocus(false); EXPECT_TRUE(app_menu_button_->HasFocus()); @@ -805,6 +811,7 @@ // Tests that a web app's theme color is set. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, ThemeColor) { + SetUpHostedApp(); aura::Window* window = browser_view_->GetWidget()->GetNativeWindow(); EXPECT_EQ(GetThemeColor(), window->GetProperty(ash::kFrameActiveColorKey)); EXPECT_EQ(GetThemeColor(), window->GetProperty(ash::kFrameInactiveColorKey)); @@ -814,6 +821,7 @@ // Make sure that for hosted apps, the height of the frame doesn't exceed the // height of the caption buttons. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, FrameSize) { + SetUpHostedApp(); const int inset = GetFrameViewAsh(browser_view_)->GetTopInset(false); EXPECT_EQ(inset, GetAshLayoutSize(ash::AshLayoutSize::kNonBrowserCaption).height()); @@ -825,12 +833,14 @@ // provider in this window configuration. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, ToolbarButtonProvider) { + SetUpHostedApp(); EXPECT_EQ(browser_view_->toolbar_button_provider(), hosted_app_button_container_); } // Test that the zoom icon appears in the title bar for hosted app windows. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, ZoomIcon) { + SetUpHostedApp(); content::WebContents* web_contents = app_browser_->tab_strip_model()->GetActiveWebContents(); zoom::ZoomController* zoom_controller = @@ -850,6 +860,7 @@ // Test that the find icon appears in the title bar for hosted app windows. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, FindIcon) { + SetUpHostedApp(); PageActionIconView* find_icon = GetPageActionIcon(PageActionIconType::kFind); EXPECT_TRUE(find_icon); @@ -864,6 +875,7 @@ // windows. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, BrowserCommandFocusToolbarAppMenu) { + SetUpHostedApp(); EXPECT_FALSE(app_menu_button_->HasFocus()); chrome::ExecuteCommand(app_browser_, IDC_FOCUS_TOOLBAR); EXPECT_TRUE(app_menu_button_->HasFocus()); @@ -873,6 +885,7 @@ // the app menu button when present in web app windows. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, BrowserCommandFocusToolbarGeolocation) { + SetUpHostedApp(); ContentSettingImageView* geolocation_icon = GrantGeolocationPermission(); EXPECT_FALSE(app_menu_button_->HasFocus()); @@ -887,6 +900,7 @@ // Tests that the show app menu command opens the app menu for web app windows. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, BrowserCommandShowAppMenu) { + SetUpHostedApp(); EXPECT_EQ(nullptr, GetAppMenu()); chrome::ExecuteCommand(app_browser_, IDC_SHOW_APP_MENU); EXPECT_NE(nullptr, GetAppMenu()); @@ -896,6 +910,7 @@ // windows. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, BrowserCommandFocusNextPane) { + SetUpHostedApp(); EXPECT_FALSE(app_menu_button_->HasFocus()); chrome::ExecuteCommand(app_browser_, IDC_FOCUS_NEXT_PANE); EXPECT_TRUE(app_menu_button_->HasFocus()); @@ -905,6 +920,7 @@ // windows. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, BrowserCommandFocusPreviousPane) { + SetUpHostedApp(); EXPECT_FALSE(app_menu_button_->HasFocus()); chrome::ExecuteCommand(app_browser_, IDC_FOCUS_PREVIOUS_PANE); EXPECT_TRUE(app_menu_button_->HasFocus()); @@ -913,6 +929,7 @@ // Tests that a web app's content settings icons can be interacted with. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, ContentSettingIcons) { + SetUpHostedApp(); for (auto* view : *content_setting_views_) EXPECT_FALSE(view->visible()); @@ -940,6 +957,7 @@ // Tests that a web app's browser action icons can be interacted with. IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, BrowserActions) { + SetUpHostedApp(); // Even though 2 are visible in the browser, no extension actions should show. ToolbarActionsBar* toolbar_actions_bar = browser_actions_container_->toolbar_actions_bar(); @@ -965,6 +983,7 @@ // Regression test for https://crbug.com/839955 IN_PROC_BROWSER_TEST_P(HostedAppNonClientFrameViewAshTest, ActiveStateOfButtonMatchesWidget) { + SetUpHostedApp(); ash::FrameCaptionButtonContainerView::TestApi test( GetFrameViewAsh(browser_view_)->caption_button_container_); EXPECT_TRUE(test.size_button()->paint_as_active());
diff --git a/chrome/browser/ui/views/frame/hosted_app_button_container.cc b/chrome/browser/ui/views/frame/hosted_app_button_container.cc index e8851ad..5da1c4c 100644 --- a/chrome/browser/ui/views/frame/hosted_app_button_container.cc +++ b/chrome/browser/ui/views/frame/hosted_app_button_container.cc
@@ -80,11 +80,10 @@ const base::TimeDelta HostedAppButtonContainer::kOriginTotalDuration = kOriginFadeInDuration + kOriginPauseDuration + kOriginFadeOutDuration; -class HostedAppButtonContainer::ContentSettingsContainer - : public views::View, - public ContentSettingImageView::Delegate { +class HostedAppButtonContainer::ContentSettingsContainer : public views::View { public: - explicit ContentSettingsContainer(BrowserView* browser_view); + explicit ContentSettingsContainer( + ContentSettingImageView::Delegate* delegate); ~ContentSettingsContainer() override = default; void UpdateContentSettingViewsVisibility() { @@ -132,26 +131,9 @@ PreferredSizeChanged(); } - // ContentSettingsImageView::Delegate: - content::WebContents* GetContentSettingWebContents() override { - return browser_view_->GetActiveWebContents(); - } - ContentSettingBubbleModelDelegate* GetContentSettingBubbleModelDelegate() - override { - return browser_view_->browser()->content_setting_bubble_model_delegate(); - } - void OnContentSettingImageBubbleShown( - ContentSettingImageModel::ImageType type) const override { - UMA_HISTOGRAM_ENUMERATION( - "HostedAppFrame.ContentSettings.ImagePressed", type, - ContentSettingImageModel::ImageType::NUM_IMAGE_TYPES); - } - // Owned by the views hierarchy. std::vector<ContentSettingImageView*> content_setting_views_; - BrowserView* browser_view_; - DISALLOW_COPY_AND_ASSIGN(ContentSettingsContainer); }; @@ -165,12 +147,7 @@ } HostedAppButtonContainer::ContentSettingsContainer::ContentSettingsContainer( - BrowserView* browser_view) - : browser_view_(browser_view) { - DCHECK( - extensions::HostedAppBrowserController::IsForExperimentalHostedAppBrowser( - browser_view->browser())); - + ContentSettingImageView::Delegate* delegate) { views::BoxLayout& layout = *SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::kHorizontal, gfx::Insets(), @@ -183,7 +160,7 @@ ContentSettingImageModel::GenerateContentSettingImageModels(); for (auto& model : models) { auto image_view = std::make_unique<ContentSettingImageView>( - std::move(model), this, + std::move(model), delegate, views::NativeWidgetAura::GetWindowTitleFontList()); // Padding around content setting icons. constexpr int kContentSettingIconInteriorPadding = 4; @@ -205,7 +182,7 @@ active_color_(active_color), inactive_color_(inactive_color), hosted_app_origin_text_(new HostedAppOriginText(browser_view->browser())), - content_settings_container_(new ContentSettingsContainer(browser_view)), + content_settings_container_(new ContentSettingsContainer(this)), page_action_icon_container_view_(new PageActionIconContainerView( {PageActionIconType::kFind, PageActionIconType::kZoom}, GetLayoutConstant(HOSTED_APP_PAGE_ACTION_ICON_SIZE), @@ -220,6 +197,9 @@ false /* interactive */)), app_menu_button_(new HostedAppMenuButton(browser_view)) { DCHECK(browser_view_); + DCHECK( + extensions::HostedAppBrowserController::IsForExperimentalHostedAppBrowser( + browser_view_->browser())); views::BoxLayout& layout = *SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::kHorizontal, @@ -314,12 +294,20 @@ g_animation_disabled_for_testing = true; } +SkColor HostedAppButtonContainer::GetIconColor() const { + return paint_as_active_ ? active_color_ : inactive_color_; +} + +SkColor HostedAppButtonContainer::GetIconInkDropColor() const { + return color_utils::IsDark(GetIconColor()) ? SK_ColorBLACK : SK_ColorWHITE; +} + void HostedAppButtonContainer::UpdateChildrenColor() { - SkColor color = paint_as_active_ ? active_color_ : inactive_color_; - hosted_app_origin_text_->SetTextColor(color); - content_settings_container_->SetIconColor(color); - page_action_icon_container_view_->SetIconColor(color); - app_menu_button_->SetIconColor(color); + SkColor icon_color = GetIconColor(); + hosted_app_origin_text_->SetTextColor(icon_color); + content_settings_container_->SetIconColor(icon_color); + page_action_icon_container_view_->SetIconColor(icon_color); + app_menu_button_->SetColors(icon_color, GetIconInkDropColor()); } gfx::Size HostedAppButtonContainer::CalculatePreferredSize() const { @@ -371,11 +359,35 @@ main_bar); } +SkColor HostedAppButtonContainer::GetPageActionInkDropColor() const { + return GetIconInkDropColor(); +} + content::WebContents* HostedAppButtonContainer::GetWebContentsForPageActionIconView() { return browser_view_->GetActiveWebContents(); } +SkColor HostedAppButtonContainer::GetContentSettingInkDropColor() const { + return GetIconInkDropColor(); +} + +content::WebContents* HostedAppButtonContainer::GetContentSettingWebContents() { + return browser_view_->GetActiveWebContents(); +} + +ContentSettingBubbleModelDelegate* +HostedAppButtonContainer::GetContentSettingBubbleModelDelegate() { + return browser_view_->browser()->content_setting_bubble_model_delegate(); +} + +void HostedAppButtonContainer::OnContentSettingImageBubbleShown( + ContentSettingImageModel::ImageType type) const { + UMA_HISTOGRAM_ENUMERATION( + "HostedAppFrame.ContentSettings.ImagePressed", type, + ContentSettingImageModel::ImageType::NUM_IMAGE_TYPES); +} + BrowserActionsContainer* HostedAppButtonContainer::GetBrowserActionsContainer() { return browser_actions_container_;
diff --git a/chrome/browser/ui/views/frame/hosted_app_button_container.h b/chrome/browser/ui/views/frame/hosted_app_button_container.h index d68f595b..912e7bc 100644 --- a/chrome/browser/ui/views/frame/hosted_app_button_container.h +++ b/chrome/browser/ui/views/frame/hosted_app_button_container.h
@@ -40,6 +40,7 @@ class HostedAppButtonContainer : public views::AccessiblePaneView, public BrowserActionsContainer::Delegate, public PageActionIconView::Delegate, + public ContentSettingImageView::Delegate, public ToolbarButtonProvider, public ImmersiveModeController::Observer, public views::WidgetObserver { @@ -103,6 +104,8 @@ const std::vector<ContentSettingImageView*>& GetContentSettingViewsForTesting() const; + SkColor GetIconColor() const; + SkColor GetIconInkDropColor() const; void UpdateChildrenColor(); // views::View: @@ -120,8 +123,17 @@ ToolbarActionsBar* main_bar) const override; // PageActionIconView::Delegate: + SkColor GetPageActionInkDropColor() const override; content::WebContents* GetWebContentsForPageActionIconView() override; + // ContentSettingImageView::Delegate: + SkColor GetContentSettingInkDropColor() const override; + content::WebContents* GetContentSettingWebContents() override; + ContentSettingBubbleModelDelegate* GetContentSettingBubbleModelDelegate() + override; + void OnContentSettingImageBubbleShown( + ContentSettingImageModel::ImageType type) const override; + // ToolbarButtonProvider: BrowserActionsContainer* GetBrowserActionsContainer() override; PageActionIconContainerView* GetPageActionIconContainerView() override;
diff --git a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc index 80d9db0a..4ef6f0f 100644 --- a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc +++ b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
@@ -49,9 +49,11 @@ HostedAppMenuButton::~HostedAppMenuButton() {} -void HostedAppMenuButton::SetIconColor(SkColor color) { +void HostedAppMenuButton::SetColors(SkColor icon_color, + SkColor ink_drop_color) { SetImage(views::Button::STATE_NORMAL, - gfx::CreateVectorIcon(kBrowserToolsIcon, color)); + gfx::CreateVectorIcon(kBrowserToolsIcon, icon_color)); + ink_drop_color_ = ink_drop_color; } void HostedAppMenuButton::StartHighlightAnimation() { @@ -80,6 +82,10 @@ base::UserMetricsAction("HostedAppMenuButtonButton_Clicked")); } +SkColor HostedAppMenuButton::GetInkDropBaseColor() const { + return ink_drop_color_; +} + void HostedAppMenuButton::FadeHighlightOff() { if (!ShouldEnterHoveredState()) { GetInkDrop()->SetHoverHighlightFadeDurationMs(
diff --git a/chrome/browser/ui/views/frame/hosted_app_menu_button.h b/chrome/browser/ui/views/frame/hosted_app_menu_button.h index e591d5c..79eac39 100644 --- a/chrome/browser/ui/views/frame/hosted_app_menu_button.h +++ b/chrome/browser/ui/views/frame/hosted_app_menu_button.h
@@ -8,6 +8,7 @@ #include "base/timer/timer.h" #include "chrome/browser/ui/views/frame/app_menu_button.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/color_palette.h" #include "ui/views/controls/button/menu_button_listener.h" class BrowserView; @@ -19,8 +20,8 @@ explicit HostedAppMenuButton(BrowserView* browser_view); ~HostedAppMenuButton() override; - // Sets the color of the menu button icon. - void SetIconColor(SkColor color); + // Sets the color of the menu button icon and highlight. + void SetColors(SkColor icon_color, SkColor ink_drop_color); // Fades the menu button highlight on and off. void StartHighlightAnimation(); @@ -30,6 +31,9 @@ const gfx::Point& point, const ui::Event* event) override; + // InkDropHostView: + SkColor GetInkDropBaseColor() const override; + private: void FadeHighlightOff(); @@ -39,6 +43,8 @@ // The containing browser view. BrowserView* browser_view_; + SkColor ink_drop_color_ = gfx::kPlaceholderColor; + base::OneShotTimer highlight_off_timer_; DISALLOW_COPY_AND_ASSIGN(HostedAppMenuButton);
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc index 0abc5c66..45e6c5fa 100644 --- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc +++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -153,16 +153,15 @@ return bubble_view_ != nullptr; } +SkColor ContentSettingImageView::GetInkDropBaseColor() const { + return delegate_->GetContentSettingInkDropColor(); +} + ContentSettingImageModel::ImageType ContentSettingImageView::GetTypeForTesting() const { return content_setting_image_model_->image_type(); } -SkColor ContentSettingImageView::GetInkDropBaseColor() const { - return icon_color_ ? icon_color_.value() - : IconLabelBubbleView::GetInkDropBaseColor(); -} - void ContentSettingImageView::OnWidgetDestroying(views::Widget* widget) { DCHECK(bubble_view_); DCHECK_EQ(bubble_view_->GetWidget(), widget);
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.h b/chrome/browser/ui/views/location_bar/content_setting_image_view.h index 17b6ce95..4a785e12 100644 --- a/chrome/browser/ui/views/location_bar/content_setting_image_view.h +++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.h
@@ -38,6 +38,9 @@ public: class Delegate { public: + // Gets the color to use for the ink highlight. + virtual SkColor GetContentSettingInkDropColor() const = 0; + // Gets the web contents the ContentSettingImageView is for. virtual content::WebContents* GetContentSettingWebContents() = 0; @@ -49,9 +52,6 @@ // Invoked when a bubble is shown. virtual void OnContentSettingImageBubbleShown( ContentSettingImageModel::ImageType type) const {} - - protected: - virtual ~Delegate() {} }; ContentSettingImageView(std::unique_ptr<ContentSettingImageModel> image_model, @@ -75,11 +75,11 @@ bool OnMousePressed(const ui::MouseEvent& event) override; bool OnKeyPressed(const ui::KeyEvent& event) override; void OnNativeThemeChanged(const ui::NativeTheme* native_theme) override; - SkColor GetInkDropBaseColor() const override; SkColor GetTextColor() const override; bool ShouldShowSeparator() const override; bool ShowBubble(const ui::Event& event) override; bool IsBubbleShowing() const override; + SkColor GetInkDropBaseColor() const override; ContentSettingImageModel::ImageType GetTypeForTesting() const;
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc index 28397eb2..963cda76 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -357,16 +357,6 @@ return highlight; } -SkColor IconLabelBubbleView::GetInkDropBaseColor() const { - const SkColor ink_color_opaque = GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_TextfieldDefaultColor); - if (ui::MaterialDesignController::IsNewerMaterialUi()) { - // Opacity of the ink drop is set elsewhere, so just use full opacity here. - return ink_color_opaque; - } - return color_utils::DeriveDefaultIconColor(ink_color_opaque); -} - std::unique_ptr<views::InkDropMask> IconLabelBubbleView::CreateInkDropMask() const { if (!LocationBarView::IsRounded())
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h index 182e563..7c0b752a 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -141,8 +141,8 @@ std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() const override; - SkColor GetInkDropBaseColor() const override; std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; + SkColor GetInkDropBaseColor() const override = 0; // views::Button: bool IsTriggerableEvent(const ui::Event& event) override;
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc index 2f055f6..36c5662 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc
@@ -84,6 +84,7 @@ protected: // IconLabelBubbleView: SkColor GetTextColor() const override { return kTestColor; } + SkColor GetInkDropBaseColor() const override { return kTestColor; } bool ShouldShowLabel() const override { return !IsShrinking() ||
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index be9a915..61a3d96 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -333,6 +333,11 @@ state); } +SkColor LocationBarView::GetIconInkDropColor() const { + return GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_TextfieldDefaultColor); +} + void LocationBarView::SetStarToggled(bool on) { if (star_view_) star_view_->SetToggled(on); @@ -749,6 +754,10 @@ //////////////////////////////////////////////////////////////////////////////// // LocationBarView, public ContentSettingImageView::Delegate implementation: +SkColor LocationBarView::GetContentSettingInkDropColor() const { + return GetIconInkDropColor(); +} + content::WebContents* LocationBarView::GetContentSettingWebContents() { return GetToolbarModel()->input_in_progress() ? nullptr : GetWebContents(); } @@ -760,6 +769,11 @@ //////////////////////////////////////////////////////////////////////////////// // LocationBarView, public PageActionIconView::Delegate implementation: + +SkColor LocationBarView::GetPageActionInkDropColor() const { + return GetIconInkDropColor(); +} + WebContents* LocationBarView::GetWebContentsForPageActionIconView() { return GetWebContents(); }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h index e441ae82..2075a15 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.h +++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -137,6 +137,9 @@ SkColor GetSecurityChipColor( security_state::SecurityLevel security_level) const; + // Returns the color to use for icon ink highlights. + SkColor GetIconInkDropColor() const; + // Returns the cached theme color tint for the location bar and results. OmniboxTint tint() const { return tint_; } @@ -239,6 +242,7 @@ content::WebContents* GetWebContents() override; // ContentSettingImageView::Delegate: + SkColor GetContentSettingInkDropColor() const override; content::WebContents* GetContentSettingWebContents() override; ContentSettingBubbleModelDelegate* GetContentSettingBubbleModelDelegate() override; @@ -373,6 +377,7 @@ const gfx::Point& p) override; // PageActionIconView::Delegate: + SkColor GetPageActionInkDropColor() const override; content::WebContents* GetWebContentsForPageActionIconView() override; // gfx::AnimationDelegate:
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.cc b/chrome/browser/ui/views/location_bar/location_icon_view.cc index 86ffa0bd..2d6bd14 100644 --- a/chrome/browser/ui/views/location_bar/location_icon_view.cc +++ b/chrome/browser/ui/views/location_bar/location_icon_view.cc
@@ -96,6 +96,10 @@ return location_bar_->ShowPageInfoDialog(contents); } +SkColor LocationIconView::GetInkDropBaseColor() const { + return location_bar_->GetIconInkDropColor(); +} + void LocationIconView::GetAccessibleNodeData(ui::AXNodeData* node_data) { if (location_bar_->GetOmniboxView()->IsEditingOrEmpty()) { node_data->role = ax::mojom::Role::kImage;
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.h b/chrome/browser/ui/views/location_bar/location_icon_view.h index 63ebb5f..1d4187e 100644 --- a/chrome/browser/ui/views/location_bar/location_icon_view.h +++ b/chrome/browser/ui/views/location_bar/location_icon_view.h
@@ -32,6 +32,7 @@ bool ShowBubble(const ui::Event& event) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; bool IsBubbleShowing() const override; + SkColor GetInkDropBaseColor() const override; // Whether we should show the tooltip for this icon or not. void set_show_tooltip(bool show_tooltip) { show_tooltip_ = show_tooltip; }
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc index dcbb75d..87edc033 100644 --- a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc +++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
@@ -49,6 +49,10 @@ return location_bar_->GetColor(OmniboxPart::LOCATION_BAR_SELECTED_KEYWORD); } +SkColor SelectedKeywordView::GetInkDropBaseColor() const { + return location_bar_->GetIconInkDropColor(); +} + gfx::Size SelectedKeywordView::CalculatePreferredSize() const { // Height will be ignored by the LocationBarView. return GetSizeForLabelWidth(full_label_.GetPreferredSize().width());
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.h b/chrome/browser/ui/views/location_bar/selected_keyword_view.h index 861f9007..0f3ea308 100644 --- a/chrome/browser/ui/views/location_bar/selected_keyword_view.h +++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
@@ -33,6 +33,7 @@ // IconLabelBubbleView: SkColor GetTextColor() const override; + SkColor GetInkDropBaseColor() const override; // views::View: gfx::Size CalculatePreferredSize() const override;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc index 07519d0a..bcd299cb 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -25,6 +25,7 @@ #include "chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.h" #include "chrome/grit/generated_resources.h" #include "components/omnibox/browser/omnibox_field_trial.h" +#include "components/omnibox/browser/omnibox_pedal.h" #include "components/omnibox/browser/omnibox_popup_model.h" #include "components/omnibox/browser/vector_icons.h" #include "components/strings/grit/components_strings.h" @@ -88,12 +89,18 @@ // Set up 'switch to tab' button. if (match.ShouldShowTabMatch()) { - const base::string16 hint = - l10n_util::GetStringUTF16(IDS_OMNIBOX_TAB_SUGGEST_HINT); - const base::string16 hint_short = - l10n_util::GetStringUTF16(IDS_OMNIBOX_TAB_SUGGEST_SHORT_HINT); - suggestion_tab_switch_button_ = std::make_unique<OmniboxTabSwitchButton>( - model_, this, hint, hint_short, omnibox::kSwitchIcon); + if (match.pedal) { + const OmniboxPedal::LabelStrings& strings = + match.pedal->GetLabelStrings(); + suggestion_tab_switch_button_ = std::make_unique<OmniboxTabSwitchButton>( + model_, this, strings.hint, strings.hint_short, omnibox::kPedalIcon); + } else { + suggestion_tab_switch_button_ = std::make_unique<OmniboxTabSwitchButton>( + model_, this, l10n_util::GetStringUTF16(IDS_OMNIBOX_TAB_SUGGEST_HINT), + l10n_util::GetStringUTF16(IDS_OMNIBOX_TAB_SUGGEST_SHORT_HINT), + omnibox::kSwitchIcon); + } + suggestion_tab_switch_button_->set_owned_by_client(); AddChildView(suggestion_tab_switch_button_.get()); } else {
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.cc b/chrome/browser/ui/views/page_action/page_action_icon_view.cc index a7d3b64..615721fb 100644 --- a/chrome/browser/ui/views/page_action/page_action_icon_view.cc +++ b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
@@ -68,12 +68,6 @@ return GetBubble() != nullptr; } -SkColor PageActionIconView::GetTextColor() const { - // Returns the color of the label shown during animation. - return GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_LabelDisabledColor); -} - bool PageActionIconView::SetCommandEnabled(bool enabled) const { DCHECK(command_updater_); command_updater_->UpdateCommandEnabled(command_id_, enabled); @@ -84,6 +78,12 @@ return false; } +SkColor PageActionIconView::GetTextColor() const { + // Returns the color of the label shown during animation. + return GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_LabelDisabledColor); +} + void PageActionIconView::GetAccessibleNodeData(ui::AXNodeData* node_data) { node_data->role = ax::mojom::Role::kButton; node_data->SetName(GetTextForTooltipAndAccessibleName()); @@ -205,16 +205,6 @@ return highlight; } -SkColor PageActionIconView::GetInkDropBaseColor() const { - const SkColor ink_color_opaque = GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_TextfieldDefaultColor); - if (ui::MaterialDesignController::IsNewerMaterialUi()) { - // Opacity of the ink drop is set elsewhere, so just use full opacity here. - return ink_color_opaque; - } - return color_utils::DeriveDefaultIconColor(ink_color_opaque); -} - std::unique_ptr<views::InkDropMask> PageActionIconView::CreateInkDropMask() const { if (!LocationBarView::IsRounded()) @@ -223,6 +213,10 @@ height() / 2.f); } +SkColor PageActionIconView::GetInkDropBaseColor() const { + return delegate_->GetPageActionInkDropColor(); +} + void PageActionIconView::OnGestureEvent(ui::GestureEvent* event) { if (event->type() == ui::ET_GESTURE_TAP) { AnimateInkDrop(views::InkDropState::ACTIVATED, event);
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.h b/chrome/browser/ui/views/page_action/page_action_icon_view.h index f0f73fb..897614d 100644 --- a/chrome/browser/ui/views/page_action/page_action_icon_view.h +++ b/chrome/browser/ui/views/page_action/page_action_icon_view.h
@@ -37,6 +37,9 @@ public: class Delegate { public: + // Gets the color to use for the ink highlight. + virtual SkColor GetPageActionInkDropColor() const = 0; + virtual content::WebContents* GetWebContentsForPageActionIconView() = 0; }; @@ -73,8 +76,6 @@ // Returns true if a related bubble is showing. bool IsBubbleShowing() const override; - SkColor GetTextColor() const override; - // Enables or disables the associated command. // Returns true if the command is enabled. bool SetCommandEnabled(bool enabled) const; @@ -89,6 +90,7 @@ virtual void OnPressed(bool activated) {} // views::IconLabelBubbleView: + SkColor GetTextColor() const override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; bool GetTooltipText(const gfx::Point& p, base::string16* tooltip) const override; @@ -106,8 +108,8 @@ std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() const override; - SkColor GetInkDropBaseColor() const override; std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; + SkColor GetInkDropBaseColor() const override; // ui::EventHandler: void OnGestureEvent(ui::GestureEvent* event) override;
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.cc b/chrome/browser/ui/views/payments/payment_request_item_list.cc index 30bf92d..a5d7425 100644 --- a/chrome/browser/ui/views/payments/payment_request_item_list.cc +++ b/chrome/browser/ui/views/payments/payment_request_item_list.cc
@@ -188,7 +188,7 @@ std::unique_ptr<PaymentRequestItemList::Item> item) { DCHECK_EQ(this, item->list()); if (!items_.empty()) - item->set_previous_row(items_.back().get()); + item->set_previous_row(items_.back()->AsWeakPtr()); items_.push_back(std::move(item)); if (items_.back()->selected()) { if (selected_item_)
diff --git a/chrome/browser/ui/views/payments/payment_request_row_view.h b/chrome/browser/ui/views/payments/payment_request_row_view.h index b234029..8cdfa1d 100644 --- a/chrome/browser/ui/views/payments/payment_request_row_view.h +++ b/chrome/browser/ui/views/payments/payment_request_row_view.h
@@ -6,13 +6,16 @@ #define CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_ROW_VIEW_H_ #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "ui/views/controls/button/button.h" namespace payments { // This class implements a clickable row of the Payment Request dialog that // darkens on hover and displays a horizontal ruler on its lower bound. -class PaymentRequestRowView : public views::Button { +class PaymentRequestRowView + : public views::Button, + public base::SupportsWeakPtr<PaymentRequestRowView> { public: // Creates a row view. If |clickable| is true, the row will be shaded on hover // and handle click events. |insets| are used as padding around the content. @@ -21,7 +24,7 @@ const gfx::Insets& insets); ~PaymentRequestRowView() override; - void set_previous_row(PaymentRequestRowView* previous_row) { + void set_previous_row(base::WeakPtr<PaymentRequestRowView> previous_row) { previous_row_ = previous_row; } @@ -55,7 +58,7 @@ // A non-owned pointer to the previous row object in the UI. Used to hide the // bottom border of the previous row when highlighting this one. May be null. - PaymentRequestRowView* previous_row_; + base::WeakPtr<PaymentRequestRowView> previous_row_; DISALLOW_COPY_AND_ASSIGN(PaymentRequestRowView); };
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc index 901ecb99..cc88250 100644 --- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -432,7 +432,7 @@ if (spec()->request_shipping()) { std::unique_ptr<PaymentRequestRowView> shipping_row = CreateShippingRow(); - shipping_row->set_previous_row(previous_row); + shipping_row->set_previous_row(previous_row->AsWeakPtr()); previous_row = shipping_row.get(); layout->StartRow(views::GridLayout::kFixedSize, 0); layout->AddView(shipping_row.release()); @@ -442,7 +442,7 @@ std::unique_ptr<PaymentRequestRowView> shipping_option_row = CreateShippingOptionRow(); if (shipping_option_row) { - shipping_option_row->set_previous_row(previous_row); + shipping_option_row->set_previous_row(previous_row->AsWeakPtr()); previous_row = shipping_option_row.get(); layout->StartRow(views::GridLayout::kFixedSize, 0); layout->AddView(shipping_option_row.release()); @@ -450,7 +450,7 @@ } std::unique_ptr<PaymentRequestRowView> payment_method_row = CreatePaymentMethodRow(); - payment_method_row->set_previous_row(previous_row); + payment_method_row->set_previous_row(previous_row->AsWeakPtr()); previous_row = payment_method_row.get(); layout->StartRow(views::GridLayout::kFixedSize, 0); layout->AddView(payment_method_row.release()); @@ -458,7 +458,7 @@ spec()->request_payer_phone()) { std::unique_ptr<PaymentRequestRowView> contact_info_row = CreateContactInfoRow(); - contact_info_row->set_previous_row(previous_row); + contact_info_row->set_previous_row(previous_row->AsWeakPtr()); previous_row = contact_info_row.get(); layout->StartRow(views::GridLayout::kFixedSize, 0); layout->AddView(contact_info_row.release());
diff --git a/chrome/browser/ui/views/simple_message_box_views.cc b/chrome/browser/ui/views/simple_message_box_views.cc index a5dcee2..355fd27 100644 --- a/chrome/browser/ui/views/simple_message_box_views.cc +++ b/chrome/browser/ui/views/simple_message_box_views.cc
@@ -21,6 +21,7 @@ #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/display/screen.h" #include "ui/gfx/native_widget_types.h" #include "ui/views/controls/message_box_view.h" #include "ui/views/widget/widget.h" @@ -130,7 +131,8 @@ } #else if (!base::MessageLoopForUI::IsCurrent() || - !ui::ResourceBundle::HasSharedInstance()) { + !ui::ResourceBundle::HasSharedInstance() || + !display::Screen::GetScreen()) { LOG(ERROR) << "Unable to show a dialog outside the UI thread message loop: " << title << " - " << message; std::move(callback).Run(chrome::MESSAGE_BOX_RESULT_NO);
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc index 5d06416..f83d1d9 100644 --- a/chrome/browser/ui/views/tabs/tab.cc +++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -5,6 +5,8 @@ #include "chrome/browser/ui/views/tabs/tab.h" #include <stddef.h> + +#include <algorithm> #include <limits> #include <utility> @@ -34,6 +36,7 @@ #include "chrome/browser/ui/views/tabs/tab_controller.h" #include "chrome/browser/ui/views/tabs/tab_icon.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" +#include "chrome/browser/ui/views/tabs/tab_style.h" #include "chrome/browser/ui/views/touch_uma/touch_uma.h" #include "chrome/common/chrome_features.h" #include "chrome/grit/generated_resources.h" @@ -73,6 +76,9 @@ #include "ui/aura/env.h" #endif +// Turn this off to revert to the old behavior. +#define USE_TAB_STYLE + using base::UserMetricsAction; using MD = ui::MaterialDesignController; @@ -119,6 +125,8 @@ flags); } +#if !defined(USE_TAB_STYLE) + // Scales |bounds| by scale and aligns so that adjacent tabs meet up exactly // during painting. const gfx::RectF ScaleAndAlignBounds(const gfx::Rect& bounds, @@ -155,17 +163,17 @@ } // Offsets each path inward by |insets|, then intersects them together. -gfx::Path OffsetAndIntersectPaths(gfx::Path& left_path, - gfx::Path& right_path, +gfx::Path OffsetAndIntersectPaths(gfx::Path* left_path, + gfx::Path* right_path, const gfx::InsetsF& insets) { // This code is not prepared to deal with vertical adjustments. DCHECK_EQ(0, insets.top()); DCHECK_EQ(0, insets.bottom()); gfx::Path complete_path; - left_path.offset(insets.left(), 0); - right_path.offset(-insets.right(), 0); - Op(left_path, right_path, SkPathOp::kIntersect_SkPathOp, &complete_path); + left_path->offset(insets.left(), 0); + right_path->offset(-insets.right(), 0); + Op(*left_path, *right_path, SkPathOp::kIntersect_SkPathOp, &complete_path); return complete_path; } @@ -269,7 +277,7 @@ right_path.offset(-origin.x(), -origin.y()); left_path.offset(-origin.x(), -origin.y()); - return OffsetAndIntersectPaths(left_path, right_path, insets.Scale(scale)); + return OffsetAndIntersectPaths(&left_path, &right_path, insets.Scale(scale)); } // Returns a path corresponding to the tab's outer border for a given tab @@ -363,6 +371,8 @@ return path; } +#endif // !defined(USE_TAB_STYLE) + } // namespace // Tab ------------------------------------------------------------------------- @@ -483,11 +493,18 @@ // When the window is maximized we don't want to shave off the edges or top // shadow of the tab, such that the user can click anywhere along the top // edge of the screen to select a tab. Ditto for immersive fullscreen. +#if defined(USE_TAB_STYLE) + *mask = GetTabStyle()->GetPath( + this, TabStyle::PathType::kHitTest, + GetWidget()->GetCompositor()->device_scale_factor(), + /* force_active */ false, TabStyle::RenderUnits::kDips); +#else const views::Widget* widget = GetWidget(); *mask = GetBorderPath( GetWidget()->GetCompositor()->device_scale_factor(), GetStrokeThickness(), GetBottomStrokeThickness(), true, widget && (widget->IsMaximized() || widget->IsFullscreen()), bounds()); +#endif return true; } @@ -514,7 +531,7 @@ favicon_bounds.set_size( gfx::Size(icon_->GetPreferredSize().width(), contents_rect.height() - favicon_bounds.y())); - if (center_favicon_) { + if (center_icon_) { // When centering the favicon, the favicon is allowed to escape the normal // contents rect. favicon_bounds.set_x(Center(width(), gfx::kFaviconSize)); @@ -582,7 +599,13 @@ std::max(contents_rect.x(), right - image_size.width()), contents_rect.y() + Center(contents_rect.height(), image_size.height()), image_size.width(), image_size.height()); - MaybeAdjustLeftForPinnedTab(&bounds, bounds.width()); + if (center_icon_) { + // When centering the alert icon, it is allowed to escape the normal + // contents rect. + bounds.set_x(Center(width(), bounds.width())); + } else { + MaybeAdjustLeftForPinnedTab(&bounds, bounds.width()); + } alert_indicator_->SetBoundsRect(bounds); } alert_indicator_->SetVisible(showing_alert_indicator_); @@ -817,6 +840,11 @@ ui::ClipRecorder clip_recorder(info.context()); // The paint recording scale for tabs is consistent along the x and y axis. const float paint_recording_scale = info.paint_recording_scale_x(); + +#if defined(USE_TAB_STYLE) + const gfx::Path clip_path = GetTabStyle()->GetPath( + this, TabStyle::PathType::kClip, paint_recording_scale); +#else // When there is a separator, animate the clip to account for it, in sync with // the separator's fading. // TODO(pkasting): Consider crossfading the favicon instead of animating the @@ -825,14 +853,21 @@ constexpr float kChildClipPadding = 2.5f; const gfx::InsetsF padding(0, kChildClipPadding + opacities.left, 0, kChildClipPadding + opacities.right); - clip_recorder.ClipPathWithAntiAliasing( + const gfx::Path clip_path = GetInteriorPath(paint_recording_scale, GetStrokeThickness(), - GetBottomStrokeThickness(), bounds(), padding)); + GetBottomStrokeThickness(), bounds(), padding); +#endif + + clip_recorder.ClipPathWithAntiAliasing(clip_path); View::PaintChildren(info); } void Tab::OnPaint(gfx::Canvas* canvas) { gfx::Path clip; +#if defined(USE_TAB_STYLE) + if (!controller_->ShouldPaintTab(this, canvas->image_scale(), &clip)) + return; +#else if (!controller_->ShouldPaintTab( this, base::BindRepeating(&GetBorderPath, canvas->image_scale(), @@ -840,6 +875,7 @@ true, false), &clip)) return; +#endif PaintTab(canvas, clip); } @@ -1006,6 +1042,92 @@ stroke_thickness + GetLayoutConstant(TABSTRIP_TOOLBAR_OVERLAP), 0); } +Tab::SeparatorOpacities Tab::GetSeparatorOpacities(bool for_layout) const { + // Something should visually separate tabs from each other and any adjacent + // new tab button. Normally, active and hovered tabs draw distinct shapes + // (via different background colors) and thus need no separators, while + // background tabs need separators between them. In single-tab mode, the + // active tab has no visible shape and thus needs separators on any side with + // an adjacent new tab button. (The other sides will be faded out below.) + float leading_opacity, trailing_opacity; + if (controller_->SingleTabMode()) { + leading_opacity = trailing_opacity = 1.f; + } else if (IsActive()) { + leading_opacity = trailing_opacity = 0; + } else { + // Fade out the trailing separator while this tab or the subsequent tab is + // hovered. If the subsequent tab is active, don't consider its hover + // animation value, lest the trailing separator on this tab disappear while + // the subsequent tab is being dragged. + const float hover_value = hover_controller_.GetAnimationValue(); + const Tab* subsequent_tab = controller_->GetAdjacentTab(this, 1); + const float subsequent_hover = + !for_layout && subsequent_tab && !subsequent_tab->IsActive() + ? float{subsequent_tab->hover_controller_.GetAnimationValue()} + : 0; + trailing_opacity = 1.f - std::max(hover_value, subsequent_hover); + + // The leading separator need not consider the previous tab's hover value, + // since if there is a previous tab that's hovered and not being dragged, it + // will draw atop this tab. + leading_opacity = 1.f - hover_value; + + const Tab* previous_tab = controller_->GetAdjacentTab(this, -1); + if (IsSelected()) { + // Since this tab is selected, its shape will be visible against adjacent + // unselected tabs, so remove the separator in those cases. + if (previous_tab && !previous_tab->IsSelected()) + leading_opacity = 0; + if (subsequent_tab && !subsequent_tab->IsSelected()) + trailing_opacity = 0; + } else if (controller_->HasVisibleBackgroundTabShapes()) { + // Since this tab is unselected, adjacent selected tabs will normally + // paint atop it, covering the separator. But if the user drags those + // selected tabs away, the exposed region looks like the window frame; and + // since background tab shapes are visible, there should be no separator. + // TODO(pkasting): https://crbug.com/876599 When a tab is animating into + // this gap, we should adjust its separator opacities as well. + if (previous_tab && previous_tab->IsSelected()) + leading_opacity = 0; + if (subsequent_tab && subsequent_tab->IsSelected()) + trailing_opacity = 0; + } + } + + // For the first or last tab in the strip, fade the leading or trailing + // separator based on the NTB position and how close to the target bounds this + // tab is. In the steady state, this hides separators on the opposite end of + // the strip from the NTB; it fades out the separators as tabs animate into + // these positions, after they pass by the other tabs; and it snaps the + // separators to full visibility immediately when animating away from these + // positions, which seems desirable. + const NewTabButtonPosition ntb_position = + controller_->GetNewTabButtonPosition(); + const gfx::Rect target_bounds = + controller_->GetTabAnimationTargetBounds(this); + const int tab_width = std::max(width(), target_bounds.width()); + const float target_opacity = + float{std::min(std::abs(x() - target_bounds.x()), tab_width)} / tab_width; + // If the tab shapes are visible, never draw end separators. + const bool always_hide_separators_on_ends = + controller_->HasVisibleBackgroundTabShapes(); + if (controller_->IsFirstVisibleTab(this) && + (ntb_position != LEADING || always_hide_separators_on_ends)) + leading_opacity = target_opacity; + if (controller_->IsLastVisibleTab(this) && + (ntb_position != AFTER_TABS || always_hide_separators_on_ends)) + trailing_opacity = target_opacity; + + // Return the opacities in physical order, rather than logical. + if (base::i18n::IsRTL()) + std::swap(leading_opacity, trailing_opacity); + return {leading_opacity, trailing_opacity}; +} + +const TabStyle* Tab::GetTabStyle() const { + return TabStyle::GetInstance(); +} + // static gfx::Insets Tab::GetContentsHorizontalInsets() { return gfx::Insets(0, GetCornerRadius() * 2); @@ -1185,23 +1307,38 @@ const bool paint_hover_effect = !active && hover_controller_.ShouldDraw(); const float scale = canvas->image_scale(); const float stroke_thickness = GetStrokeThickness(active); +#if !defined(USE_TAB_STYLE) const float bottom_offset = GetBottomStrokeThickness(active); +#endif const auto paint_fill = [&](gfx::Canvas* canvas) { +#if defined(USE_TAB_STYLE) + const gfx::Path fill_path = + GetTabStyle()->GetPath(this, TabStyle::PathType::kFill, scale, active); +#else // When there's a border, we want the stroke to cover up the edge of the // fill path (https://crbug.com/873003), so set the fill path halfway // between the inner path and the border paths. When there's no stroke, // |stroke_thickness| is 0 and the fill, inner, and stroke paths are all // identical. - gfx::Path fill_path = + const gfx::Path fill_path = GetInteriorPath(scale, stroke_thickness / 2, bottom_offset, bounds()); +#endif PaintTabBackgroundFill(canvas, fill_path, active, paint_hover_effect, active_color, inactive_color, fill_id, y_inset); }; const auto paint_stroke = [&](gfx::Canvas* canvas) { +#if defined(USE_TAB_STYLE) + const TabStyle* tab_style = GetTabStyle(); + gfx::Path interior_path = tab_style->GetPath( + this, TabStyle::PathType::kInsideBorder, scale, active); + gfx::Path outer_path = tab_style->GetPath( + this, TabStyle::PathType::kOutsideBorder, scale, active); +#else gfx::Path interior_path = GetInteriorPath(scale, stroke_thickness, bottom_offset, bounds()); gfx::Path outer_path = GetBorderPath(scale, stroke_thickness, bottom_offset, false, false, bounds()); +#endif PaintTabBackgroundStroke(canvas, interior_path, outer_path, active, stroke_color); }; @@ -1332,22 +1469,28 @@ gfx::ScopedCanvas scoped_canvas(canvas); const float scale = canvas->UndoDeviceScaleFactor(); +#if defined(USE_TAB_STYLE) + TabStyle::SeparatorBounds separator_bounds = + GetTabStyle()->GetSeparatorBounds(this, scale); +#else + TabStyle::SeparatorBounds separator_bounds; const gfx::RectF aligned_bounds = ScaleAndAlignBounds(bounds(), scale, GetStrokeThickness()); const int corner_radius = GetCornerRadius(); const float separator_height = GetTabSeparatorHeight() * scale; - gfx::RectF leading_separator_bounds( + separator_bounds.leading = gfx::RectF( aligned_bounds.x() + corner_radius * scale, aligned_bounds.y() + (aligned_bounds.height() - separator_height) / 2, kSeparatorThickness * scale, separator_height); - gfx::RectF trailing_separator_bounds = leading_separator_bounds; - trailing_separator_bounds.set_x( + separator_bounds.trailing = separator_bounds.leading; + separator_bounds.trailing.set_x( aligned_bounds.right() - (corner_radius + kSeparatorThickness) * scale); gfx::PointF origin(bounds().origin()); origin.Scale(scale); - leading_separator_bounds.Offset(-origin.x(), -origin.y()); - trailing_separator_bounds.Offset(-origin.x(), -origin.y()); + separator_bounds.leading.Offset(-origin.x(), -origin.y()); + separator_bounds.trailing.Offset(-origin.x(), -origin.y()); +#endif const SkColor separator_base_color = controller_->GetTabSeparatorColor(); const auto separator_color = [separator_base_color](float opacity) { @@ -1359,9 +1502,9 @@ cc::PaintFlags flags; flags.setAntiAlias(true); flags.setColor(separator_color(separator_opacities.left)); - canvas->DrawRect(leading_separator_bounds, flags); + canvas->DrawRect(separator_bounds.leading, flags); flags.setColor(separator_color(separator_opacities.right)); - canvas->DrawRect(trailing_separator_bounds, flags); + canvas->DrawRect(separator_bounds.trailing, flags); } void Tab::UpdateIconVisibility() { @@ -1373,7 +1516,7 @@ // This prevents the icon and text from sliding left at the end of closing // a non-narrow tab. if (!closing_) { - center_favicon_ = false; + center_icon_ = false; extra_padding_before_content_ = false; } @@ -1445,15 +1588,16 @@ if (showing_close_button_ || show_on_hover) available_width -= close_button_width; - // If no other controls are visible, show favicon even though we - // don't have enough space. We'll clip the favicon in PaintChildren(). - if (!showing_close_button_ && !showing_alert_indicator_ && !showing_icon_ && - has_favicon) { - showing_icon_ = true; + // If no other controls are visible, show the alert icon or the favicon + // even though we don't have enough space. We'll clip the icon in + // PaintChildren(). + if (!showing_close_button_ && !showing_alert_indicator_ && !showing_icon_) { + showing_alert_indicator_ = has_alert_icon; + showing_icon_ = !showing_alert_indicator_ && has_favicon; // See comments near top of function on why this conditional is here. if (!closing_) - center_favicon_ = true; + center_icon_ = true; } } @@ -1477,88 +1621,6 @@ (width() >= (GetPinnedWidth() + kPinnedTabExtraWidthToRenderAsNormal)); } -Tab::SeparatorOpacities Tab::GetSeparatorOpacities(bool for_layout) const { - // Something should visually separate tabs from each other and any adjacent - // new tab button. Normally, active and hovered tabs draw distinct shapes - // (via different background colors) and thus need no separators, while - // background tabs need separators between them. In single-tab mode, the - // active tab has no visible shape and thus needs separators on any side with - // an adjacent new tab button. (The other sides will be faded out below.) - float leading_opacity, trailing_opacity; - if (controller_->SingleTabMode()) { - leading_opacity = trailing_opacity = 1.f; - } else if (IsActive()) { - leading_opacity = trailing_opacity = 0; - } else { - // Fade out the trailing separator while this tab or the subsequent tab is - // hovered. If the subsequent tab is active, don't consider its hover - // animation value, lest the trailing separator on this tab disappear while - // the subsequent tab is being dragged. - const float hover_value = hover_controller_.GetAnimationValue(); - const Tab* subsequent_tab = controller_->GetAdjacentTab(this, 1); - const float subsequent_hover = - !for_layout && subsequent_tab && !subsequent_tab->IsActive() - ? float{subsequent_tab->hover_controller_.GetAnimationValue()} - : 0; - trailing_opacity = 1.f - std::max(hover_value, subsequent_hover); - - // The leading separator need not consider the previous tab's hover value, - // since if there is a previous tab that's hovered and not being dragged, it - // will draw atop this tab. - leading_opacity = 1.f - hover_value; - - const Tab* previous_tab = controller_->GetAdjacentTab(this, -1); - if (IsSelected()) { - // Since this tab is selected, its shape will be visible against adjacent - // unselected tabs, so remove the separator in those cases. - if (previous_tab && !previous_tab->IsSelected()) - leading_opacity = 0; - if (subsequent_tab && !subsequent_tab->IsSelected()) - trailing_opacity = 0; - } else if (controller_->HasVisibleBackgroundTabShapes()) { - // Since this tab is unselected, adjacent selected tabs will normally - // paint atop it, covering the separator. But if the user drags those - // selected tabs away, the exposed region looks like the window frame; and - // since background tab shapes are visible, there should be no separator. - // TODO(pkasting): https://crbug.com/876599 When a tab is animating into - // this gap, we should adjust its separator opacities as well. - if (previous_tab && previous_tab->IsSelected()) - leading_opacity = 0; - if (subsequent_tab && subsequent_tab->IsSelected()) - trailing_opacity = 0; - } - } - - // For the first or last tab in the strip, fade the leading or trailing - // separator based on the NTB position and how close to the target bounds this - // tab is. In the steady state, this hides separators on the opposite end of - // the strip from the NTB; it fades out the separators as tabs animate into - // these positions, after they pass by the other tabs; and it snaps the - // separators to full visibility immediately when animating away from these - // positions, which seems desirable. - const NewTabButtonPosition ntb_position = - controller_->GetNewTabButtonPosition(); - const gfx::Rect target_bounds = - controller_->GetTabAnimationTargetBounds(this); - const int tab_width = std::max(width(), target_bounds.width()); - const float target_opacity = - float{std::min(std::abs(x() - target_bounds.x()), tab_width)} / tab_width; - // If the tab shapes are visible, never draw end separators. - const bool always_hide_separators_on_ends = - controller_->HasVisibleBackgroundTabShapes(); - if (controller_->IsFirstVisibleTab(this) && - (ntb_position != LEADING || always_hide_separators_on_ends)) - leading_opacity = target_opacity; - if (controller_->IsLastVisibleTab(this) && - (ntb_position != AFTER_TABS || always_hide_separators_on_ends)) - trailing_opacity = target_opacity; - - // Return the opacities in physical order, rather than logical. - if (base::i18n::IsRTL()) - std::swap(leading_opacity, trailing_opacity); - return {leading_opacity, trailing_opacity}; -} - float Tab::GetHoverOpacity() const { // Opacity boost varies on tab width. The interpolation is nonlinear so // that most tabs will fall on the low end of the opacity range, but very
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h index 45db570..ea4ddb8 100644 --- a/chrome/browser/ui/views/tabs/tab.h +++ b/chrome/browser/ui/views/tabs/tab.h
@@ -186,6 +186,21 @@ // Returns the insets to use for laying out tab contents. gfx::Insets GetContentsInsets() const; + // Contains values 0..1 representing the opacity of the corresponding + // separators. These are physical and not logical, so "left" is the left + // separator in both LTR and RTL. + struct SeparatorOpacities { + float left = 0, right = 0; + }; + + // Returns the opacities of the separators. If |for_layout| is true, returns + // the "layout" opacities, which ignore the effects of surrounding tabs' hover + // effects and consider only the current tab's state. + SeparatorOpacities GetSeparatorOpacities(bool for_layout) const; + + // Returns the TabStyle associated with this tab. + const class TabStyle* GetTabStyle() const; + // Returns the horizontal insets to use for laying out tab contents. static gfx::Insets GetContentsHorizontalInsets(); @@ -233,13 +248,6 @@ TabCloseButtonVisibilityWhenNotStacked); FRIEND_TEST_ALL_PREFIXES(TabTest, TitleTextHasSufficientContrast); - // Contains values 0..1 representing the opacity of the corresponding - // separators. These are physical and not logical, so "left" is the left - // separator in both LTR and RTL. - struct SeparatorOpacities { - float left = 0, right = 0; - }; - // Invoked from Layout to adjust the position of the favicon or alert // indicator for pinned tabs. The visual_width parameter is how wide the // icon looks (rather than how wide the bounds are). @@ -287,11 +295,6 @@ // pinned tab. bool ShouldRenderAsNormalTab() const; - // Returns the opacities of the separators. If |for_layout| is true, returns - // the "layout" opacities, which ignore the effects of surrounding tabs' hover - // effects and consider only the current tab's state. - SeparatorOpacities GetSeparatorOpacities(bool for_layout) const; - // Returns the final hover opacity for this tab (considers tab width). float GetHoverOpacity() const; @@ -346,10 +349,10 @@ // The offset used to paint the inactive background image. int background_offset_; - // For narrow tabs, we show the favicon even if it won't completely fit. - // In this case, we need to center the favicon within the tab; it will be - // clipped to fit. - bool center_favicon_ = false; + // For narrow tabs, we show the alert icon or, if there is no alert icon, the + // favicon even if it won't completely fit. In this case, we need to center + // the icon within the tab; it will be clipped to fit. + bool center_icon_ = false; // Whether we're showing the icon. It is cached so that we can detect when it // changes and layout appropriately.
diff --git a/chrome/browser/ui/views/tabs/tab_controller.h b/chrome/browser/ui/views/tabs/tab_controller.h index 593834995..b2f29332 100644 --- a/chrome/browser/ui/views/tabs/tab_controller.h +++ b/chrome/browser/ui/views/tabs/tab_controller.h
@@ -30,7 +30,6 @@ // Controller for tabs. class TabController { public: - virtual const ui::ListSelectionModel& GetSelectionModel() const = 0; // Returns true if multiple selection is supported. @@ -126,6 +125,7 @@ const base::RepeatingCallback<gfx::Path(const gfx::Rect&)>& border_callback, gfx::Path* clip) = 0; + virtual bool ShouldPaintTab(const Tab* tab, float scale, gfx::Path* clip) = 0; // Returns the thickness of the stroke around the active tab in DIP. Returns // 0 if there is no stroke.
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc index c4b8845..f1710f5 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -1214,6 +1214,7 @@ } } + ClearIsDraggingTabs(); ClearTabDraggingInfo(); attached_tabstrip_->DraggedTabsDetached(); attached_tabstrip_ = NULL; @@ -1549,7 +1550,9 @@ GetAttachedBrowserWidget()->EndMoveLoop(); } - ClearTabDraggingInfo(); + // "IsDraggingTabs" flag needs to be cleared since some part of CompleteDrag() + // assumes it's cleared beforehand. See https://crbug.com/892221. + ClearIsDraggingTabs(); if (type != TAB_DESTROYED) { // We only finish up the drag if we were actually dragging. If start_drag_ @@ -1573,6 +1576,10 @@ RevertDrag(); } // else case the only tab we were dragging was deleted. Nothing to do. + // Clear tab dragging info after the complete/revert as CompleteDrag() may + // need to use some of the properties. + ClearTabDraggingInfo(); + // Clear out drag data so we don't attempt to do anything with it. drag_data_.clear(); @@ -2113,22 +2120,32 @@ #endif } -void TabDragController::ClearTabDraggingInfo() { +void TabDragController::ClearIsDraggingTabs() { #if defined(OS_CHROMEOS) TabStrip* dragged_tabstrip = attached_tabstrip_ ? attached_tabstrip_ : source_tabstrip_; DCHECK(!dragged_tabstrip->IsDragSessionActive() || !active_); // Do not clear the dragging info properties for a to-be-destroyed window. - // They will be cleared later in Window's destrutor. It's intentional as + // They will be cleared later in Window's destructor. It's intentional as // ash::SplitViewController::TabDraggedWindowObserver listens to both // OnWindowDestroying() event and the window properties change event, and uses // the two events to decide what to do next. if (GetModel(dragged_tabstrip)->empty()) return; + GetWindowForTabDraggingProperties(dragged_tabstrip) + ->ClearProperty(ash::kIsDraggingTabsKey); +#endif +} + +void TabDragController::ClearTabDraggingInfo() { +#if defined(OS_CHROMEOS) + TabStrip* dragged_tabstrip = + attached_tabstrip_ ? attached_tabstrip_ : source_tabstrip_; + DCHECK(!dragged_tabstrip->IsDragSessionActive() || !active_); + aura::Window* dragged_window = GetWindowForTabDraggingProperties(dragged_tabstrip); - dragged_window->ClearProperty(ash::kIsDraggingTabsKey); dragged_window->ClearProperty(ash::kTabDraggingSourceWindowKey); dragged_window->ClearProperty(ash::kTabDroppedWindowStateTypeKey); #endif
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h index a028f08..b82ccd0 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.h +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -492,6 +492,11 @@ // whenever the dragged tabs are attached to a new tabstrip. void SetTabDraggingInfo(); + // Clears the flag to indicate that the tab dragging is happening in the + // tabstrip. This is separated from ClearTabDraggingInfo() since this needs + // to happen slightly before ClearTabDraggingInfo(). + void ClearIsDraggingTabs(); + // Clears the tab dragging info for the current dragged tabstrip. This // function is supposed to be called whenever the dragged tabs are detached // from the old tabstrip or the tab dragging is ended.
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index c083a87a..0181b3b2e 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -36,6 +36,7 @@ #include "chrome/browser/ui/views/tabs/tab_strip_controller.h" #include "chrome/browser/ui/views/tabs/tab_strip_layout.h" #include "chrome/browser/ui/views/tabs/tab_strip_observer.h" +#include "chrome/browser/ui/views/tabs/tab_style.h" #include "chrome/browser/ui/views/touch_uma/touch_uma.h" #include "chrome/grit/generated_resources.h" #include "chrome/grit/theme_resources.h" @@ -815,7 +816,7 @@ } bool TabStrip::SupportsMultipleSelection() { - // TODO: currently only allow single selection in touch layout mode. + // Currently we only allow single selection in touch layout mode. return touch_layout_ == nullptr; } @@ -1083,6 +1084,51 @@ return true; } +bool TabStrip::ShouldPaintTab(const Tab* tab, float scale, gfx::Path* clip) { + if (!MaySetClip()) + return true; + + int index = GetModelIndexOfTab(tab); + if (index == -1) + return true; // Tab is closing, paint it all. + + int active_index = IsStackingDraggedTabs() ? controller_->GetActiveIndex() + : touch_layout_->active_index(); + if (active_index == tab_count()) + active_index--; + + const gfx::Rect& current_bounds = tab_at(index)->bounds(); + if (index < active_index) { + const Tab* next_tab = tab_at(index + 1); + const gfx::Rect& next_bounds = next_tab->bounds(); + if (current_bounds.x() == next_bounds.x()) + return false; + + if (current_bounds.x() > next_bounds.x()) + return true; // Can happen during dragging. + + *clip = tab->GetTabStyle()->GetPath( + next_tab, TabStyle::PathType::kOutsideBorder, scale, false, + TabStyle::RenderUnits::kDips); + + clip->offset(SkIntToScalar(next_bounds.x() - current_bounds.x()), 0); + } else if (index > active_index && index > 0) { + const Tab* prev_tab = tab_at(index - 1); + const gfx::Rect& previous_bounds = prev_tab->bounds(); + if (current_bounds.x() == previous_bounds.x()) + return false; + + if (current_bounds.x() < previous_bounds.x()) + return true; // Can happen during dragging. + + *clip = tab->GetTabStyle()->GetPath( + prev_tab, TabStyle::PathType::kOutsideBorder, scale, false, + TabStyle::RenderUnits::kDips); + clip->offset(SkIntToScalar(previous_bounds.x() - current_bounds.x()), 0); + } + return true; +} + int TabStrip::GetStrokeThickness() const { return controller_->ShouldDrawStrokes() ? 1 : 0; }
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h index b237f4d..10bd8cd5 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.h +++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -5,7 +5,9 @@ #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_ #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_ +#include <map> #include <memory> +#include <utility> #include <vector> #include "base/compiler_specific.h" @@ -248,6 +250,7 @@ const base::RepeatingCallback<gfx::Path(const gfx::Rect&)>& border_callback, gfx::Path* clip) override; + bool ShouldPaintTab(const Tab* tab, float scale, gfx::Path* clip) override; int GetStrokeThickness() const override; bool CanPaintThrobberToLayer() const override; bool HasVisibleBackgroundTabShapes() const override;
diff --git a/chrome/browser/ui/views/tabs/tab_style.cc b/chrome/browser/ui/views/tabs/tab_style.cc new file mode 100644 index 0000000..3a0a4d2 --- /dev/null +++ b/chrome/browser/ui/views/tabs/tab_style.cc
@@ -0,0 +1,276 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/tabs/tab_style.h" + +#include "base/no_destructor.h" +#include "base/numerics/ranges.h" +#include "chrome/browser/ui/layout_constants.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/tabs/tab.h" +#include "chrome/browser/ui/views/tabs/tab_controller.h" +#include "ui/views/widget/widget.h" + +namespace { + +// Returns whether we should extend the hit test region for Fitts' Law. +bool ShouldExtendHitTest(const Tab* tab) { + const views::Widget* widget = tab->GetWidget(); + return widget->IsMaximized() || widget->IsFullscreen(); +} + +// Given a tab of width |width|, returns the radius to use for the corners. +float GetTopCornerRadiusForWidth(int width) { + // Get the width of the top of the tab by subtracting the width of the outer + // corners. + const int ideal_radius = Tab::GetCornerRadius(); + const int top_width = width - ideal_radius * 2; + + // To maintain a round-rect appearance, ensure at least one third of the top + // of the tab is flat. + const float radius = top_width / 3.f; + return base::ClampToRange<float>(radius, 0, ideal_radius); +} + +// Scales |bounds| by scale and aligns so that adjacent tabs meet up exactly +// during painting. +const gfx::RectF ScaleAndAlignBounds(const gfx::Rect& bounds, + float scale, + float stroke_thickness) { + // Convert to layout bounds. We must inset the width such that the right edge + // of one tab's layout bounds is the same as the left edge of the next tab's; + // this way the two tabs' separators will be drawn at the same coordinate. + gfx::RectF aligned_bounds(bounds); + const int corner_radius = Tab::GetCornerRadius(); + // Note: This intentionally doesn't subtract TABSTRIP_TOOLBAR_OVERLAP from the + // bottom inset, because we want to pixel-align the bottom of the stroke, not + // the bottom of the overlap. + gfx::InsetsF layout_insets(stroke_thickness, corner_radius, stroke_thickness, + corner_radius + Tab::kSeparatorThickness); + aligned_bounds.Inset(layout_insets); + + // Scale layout bounds from DIP to px. + aligned_bounds.Scale(scale); + + // Snap layout bounds to nearest pixels so we get clean lines. + const float x = std::round(aligned_bounds.x()); + const float y = std::round(aligned_bounds.y()); + // It's important to round the right edge and not the width, since rounding + // both x and width would mean the right edge would accumulate error. + const float right = std::round(aligned_bounds.right()); + const float bottom = std::round(aligned_bounds.bottom()); + aligned_bounds = gfx::RectF(x, y, right - x, bottom - y); + + // Convert back to full bounds. It's OK that the outer corners of the curves + // around the separator may not be snapped to the pixel grid as a result. + aligned_bounds.Inset(-layout_insets.Scale(scale)); + return aligned_bounds; +} + +class GM2TabStyle : public TabStyle { + public: + gfx::Path GetPath( + const Tab* tab, + PathType path_type, + float scale, + bool force_active = false, + RenderUnits render_units = RenderUnits::kPixels) const override { + const float stroke_thickness = tab->GetStrokeThickness(force_active); + + // We'll do the entire path calculation in aligned pixels. + // TODO(dfried): determine if we actually want to use |stroke_thickness| as + // the inset in this case. + gfx::RectF aligned_bounds = + ScaleAndAlignBounds(tab->bounds(), scale, stroke_thickness); + + if (path_type == PathType::kClip) { + // When there is a separator, animate the clip to account for it, in sync + // with the separator's fading. + // TODO(pkasting): Consider crossfading the favicon instead of animating + // the clip, especially if other children get crossfaded. + const auto opacities = tab->GetSeparatorOpacities(true); + constexpr float kChildClipPadding = 2.5f; + aligned_bounds.Inset( + gfx::InsetsF(0.0f, kChildClipPadding + opacities.left, 0.0f, + kChildClipPadding + opacities.right)); + } + + // Calculate the corner radii. Note that corner radius is based on original + // tab width (in DIP), not our new, scaled-and-aligned bounds. + const float radius = GetTopCornerRadiusForWidth(tab->width()) * scale; + float top_radius = radius; + float bottom_radius = radius; + + // Compute |extension| as the width outside the separators. This is a + // fixed value equal to the normal corner radius. + const float extension = Tab::GetCornerRadius() * scale; + + // Calculate the bounds of the actual path. + const float left = aligned_bounds.x(); + const float right = aligned_bounds.right(); + float tab_top = aligned_bounds.y(); + float tab_left = left + extension; + float tab_right = right - extension; + + // Overlap the toolbar below us so that gaps don't occur when rendering at + // non-integral display scale factors. + const float extended_bottom = aligned_bounds.bottom(); + const float bottom_extension = + GetLayoutConstant(TABSTRIP_TOOLBAR_OVERLAP) * scale; + float tab_bottom = extended_bottom - bottom_extension; + + // Path-specific adjustments: + const float stroke_adjustment = stroke_thickness * scale; + if (path_type == PathType::kInsideBorder || path_type == PathType::kClip) { + // Inside border runs |stroke_thickness| inside the outer stroke. + tab_left += stroke_adjustment; + tab_right -= stroke_adjustment; + tab_top += stroke_adjustment; + top_radius -= stroke_adjustment; + } else if (path_type == PathType::kFill) { + tab_left += 0.5f * stroke_adjustment; + tab_right -= 0.5f * stroke_adjustment; + tab_top += 0.5f * stroke_adjustment; + top_radius -= 0.5f * stroke_adjustment; + tab_bottom -= 0.5f * stroke_adjustment; + bottom_radius -= 0.5f * stroke_adjustment; + } else if (path_type == PathType::kOutsideBorder || + path_type == PathType::kHitTest) { + // Outside border needs to draw its bottom line a stroke width above the + // bottom of the tab, to line up with the stroke that runs across the rest + // of the bottom of the tab bar (when strokes are enabled). + tab_bottom -= stroke_adjustment; + bottom_radius -= stroke_adjustment; + } + const bool extend_to_top = + (path_type == PathType::kHitTest) && ShouldExtendHitTest(tab); + + // When the radius shrinks, it leaves a gap between the bottom corners and + // the edge of the tab. Make sure we account for this - and for any + // adjustment we may have made to the location of the tab! + const float corner_gap = (right - tab_right) - bottom_radius; + + gfx::Path path; + + // We will go clockwise from the lower left. We start in the overlap + // region, preventing a gap between toolbar and tabstrip. + // TODO(dfried): verify that the we actually want to start the stroke for + // the exterior path outside the region; we might end up rendering an + // extraneous descending pixel on displays with odd scaling and nonzero + // stroke width. + + // Start with the left side of the shape. + + // Draw everything left of the bottom-left corner of the tab. + // ╭─────────╮ + // │ Content │ + // ┏━╯ ╰─┐ + path.moveTo(left, extended_bottom); + path.lineTo(left, tab_bottom); + path.lineTo(left + corner_gap, tab_bottom); + + // Draw the bottom-left arc. + // ╭─────────╮ + // │ Content │ + // ┌─╝ ╰─┐ + path.arcTo(bottom_radius, bottom_radius, 0, SkPath::kSmall_ArcSize, + SkPath::kCCW_Direction, tab_left, tab_bottom - bottom_radius); + + // Draw the ascender and top arc, if present. + if (extend_to_top) { + // ┎─────────╮ + // ┃ Content │ + // ┌─╯ ╰─┐ + path.lineTo(tab_left, tab_top); + } else { + // ╔─────────╮ + // ┃ Content │ + // ┌─╯ ╰─┐ + path.lineTo(tab_left, tab_top + top_radius); + path.arcTo(top_radius, top_radius, 0, SkPath::kSmall_ArcSize, + SkPath::kCW_Direction, tab_left + top_radius, tab_top); + } + + // Draw the top crossbar and top-right curve, if present. + if (extend_to_top) { + // ┌━━━━━━━━━┑ + // │ Content │ + // ┌─╯ ╰─┐ + path.lineTo(tab_right, tab_top); + + } else { + // ╭━━━━━━━━━╗ + // │ Content │ + // ┌─╯ ╰─┐ + path.lineTo(tab_right - top_radius, tab_top); + path.arcTo(top_radius, top_radius, 0, SkPath::kSmall_ArcSize, + SkPath::kCW_Direction, tab_right, tab_top + top_radius); + } + + // Draw the descender and bottom-right arc. + // ╭─────────╮ + // │ Content ┃ + // ┌─╯ ╚─┐ + path.lineTo(tab_right, tab_bottom - bottom_radius); + path.arcTo(bottom_radius, bottom_radius, 0, SkPath::kSmall_ArcSize, + SkPath::kCCW_Direction, right - corner_gap, tab_bottom); + + // Draw everything right of the bottom-right corner of the tab. + // ╭─────────╮ + // │ Content │ + // ┌─╯ ╰━┓ + path.lineTo(right, tab_bottom); + path.lineTo(right, extended_bottom); + + // Finish the path. + path.close(); + + // Convert path to be relative to the tab origin. + gfx::PointF origin(tab->origin()); + origin.Scale(scale); + path.offset(-origin.x(), -origin.y()); + + // Possibly convert back to DIPs. + if (render_units == RenderUnits::kDips && scale != 1.0f) + path.transform(SkMatrix::MakeScale(1.f / scale)); + + return path; + } + + SeparatorBounds GetSeparatorBounds(const Tab* tab, + float scale) const override { + const gfx::RectF aligned_bounds = + ScaleAndAlignBounds(tab->bounds(), scale, tab->GetStrokeThickness()); + const int corner_radius = Tab::GetCornerRadius() * scale; + const float separator_height = Tab::GetTabSeparatorHeight() * scale; + const float separator_thickness = Tab::kSeparatorThickness * scale; + + SeparatorBounds separator_bounds; + + separator_bounds.leading = gfx::RectF( + aligned_bounds.x() + corner_radius, + aligned_bounds.y() + (aligned_bounds.height() - separator_height) / 2, + separator_thickness, separator_height); + + separator_bounds.trailing = separator_bounds.leading; + separator_bounds.trailing.set_x(aligned_bounds.right() - + (corner_radius + separator_thickness)); + + gfx::PointF origin(tab->bounds().origin()); + origin.Scale(scale); + separator_bounds.leading.Offset(-origin.x(), -origin.y()); + separator_bounds.trailing.Offset(-origin.x(), -origin.y()); + + return separator_bounds; + } +}; + +} // namespace + +// static +const TabStyle* TabStyle::GetInstance() { + static base::NoDestructor<GM2TabStyle> instance; + + return instance.get(); +}
diff --git a/chrome/browser/ui/views/tabs/tab_style.h b/chrome/browser/ui/views/tabs/tab_style.h new file mode 100644 index 0000000..8601dec --- /dev/null +++ b/chrome/browser/ui/views/tabs/tab_style.h
@@ -0,0 +1,85 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_STYLE_H_ +#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STYLE_H_ + +#include "base/macros.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/path.h" + +class Tab; + +// Used to generate a number of outlines for clipping, border painting, +// interior fill, etc. for tabs. +class TabStyle { + public: + // The different types of path GetPath() can return. Different paths are used + // in different situations, but most (excluding |kClip|) are roughly the same + // shape. + enum class PathType { + // Interior fill outline. Extends halfway into the border so there are no + // gaps between border and fill. + kFill, + // Inside path of the border. Border is currently the difference between + // outside and inside, allowing for a varying thickness of stroke. + kInsideBorder, + // Outside path of the border. Border is currently the difference between + // outside and inside, allowing for a varying thickness of stroke. + kOutsideBorder, + // The hit test region. May be extended into a rectangle that touches the + // top of the bounding box when the window is maximized, for Fitts' Law. + kHitTest, + // The area inside the tab where children can be rendered, used to clip + // child views. Does not have to be the same shape as the border. + kClip + }; + + // How we want the resulting path scaled. + enum class RenderUnits { + // The path is in pixels, and should have its internal area nicely aligned + // to pixel boundaries. + kPixels, + // The path is in DIPs. It will likely be calculated in pixels and then + // scaled back down. + kDips + }; + + // If we want to draw vertical separators between tabs, these are the leading + // and trailing separator stroke rectangles. + struct SeparatorBounds { + gfx::RectF leading; + gfx::RectF trailing; + }; + + // Gets the specific |path_type| associated with the specific |tab|. + // If |force_active| is true, applies an active appearance on the tab (usually + // involving painting an optional stroke) even if the tab is not the active + // tab. + virtual gfx::Path GetPath( + const Tab* tab, + PathType path_type, + float scale, + bool force_active = false, + RenderUnits render_units = RenderUnits::kPixels) const = 0; + + // Gets the bounds for the leading and trailing separators for a tab. + virtual SeparatorBounds GetSeparatorBounds(const Tab* tab, + float scale) const = 0; + + // Gets the currently active tab style. + // TODO(dfried): As we move more of the rendering code into TabStyle from + // Tab, we may need to have one instance of TabStyle per tab instead of a + // singleton (e.g. for caching purposes). + static const TabStyle* GetInstance(); + + protected: + // Avoid implicitly-deleted constructor. + TabStyle() = default; + + private: + DISALLOW_COPY_AND_ASSIGN(TabStyle); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STYLE_H_
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc index 0e6048b..4aef0d84 100644 --- a/chrome/browser/ui/views/tabs/tab_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -6,6 +6,8 @@ #include <stddef.h> +#include <utility> + #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/layout_constants.h" @@ -83,6 +85,9 @@ gfx::Path* clip) override { return true; } + bool ShouldPaintTab(const Tab* tab, float scale, gfx::Path* clip) override { + return true; + } int GetStrokeThickness() const override { return 0; } bool CanPaintThrobberToLayer() const override { return paint_throbber_to_layer_; @@ -157,7 +162,7 @@ return tab.title_->bounds().width(); } - static void EndTitleAnimation(Tab& tab) { tab.title_animation_.End(); } + static void EndTitleAnimation(Tab* tab) { tab->title_animation_.End(); } static void LayoutTab(Tab* tab) { tab->Layout(); } @@ -205,11 +210,13 @@ switch (VisibleIconCount(tab)) { case 1: EXPECT_FALSE(tab.showing_close_button_); - if (tab.data_.alert_state == TabAlertState::NONE || - tab.center_favicon_) + if (tab.data_.alert_state == TabAlertState::NONE) { EXPECT_FALSE(tab.showing_alert_indicator_); - if (tab.center_favicon_) EXPECT_TRUE(tab.showing_icon_); + } else { + EXPECT_FALSE(tab.showing_icon_); + EXPECT_TRUE(tab.showing_alert_indicator_); + } break; case 2: EXPECT_TRUE(tab.showing_icon_); @@ -228,7 +235,7 @@ // are fully within the contents bounds. const gfx::Rect contents_bounds = tab.GetContentsBounds(); if (tab.showing_icon_) { - if (tab.center_favicon_) { + if (tab.center_icon_) { EXPECT_LE(tab.icon_->x(), contents_bounds.x()); } else { EXPECT_LE(contents_bounds.x(), tab.icon_->x()); @@ -252,7 +259,13 @@ EXPECT_LE(tab.title_->bounds().right(), GetAlertIndicatorBounds(tab).x()); } - EXPECT_LE(GetAlertIndicatorBounds(tab).right(), contents_bounds.right()); + if (tab.center_icon_) { + EXPECT_LE(contents_bounds.right(), + GetAlertIndicatorBounds(tab).right()); + } else { + EXPECT_LE(GetAlertIndicatorBounds(tab).right(), + contents_bounds.right()); + } EXPECT_LE(contents_bounds.y(), GetAlertIndicatorBounds(tab).y()); EXPECT_LE(GetAlertIndicatorBounds(tab).bottom(), contents_bounds.bottom()); @@ -736,7 +749,7 @@ TabRendererData data; data.show_icon = false; tab.SetData(data); - EndTitleAnimation(tab); + EndTitleAnimation(&tab); EXPECT_FALSE(icon->visible()); // Title should be placed where the favicon was. EXPECT_EQ(icon_x, GetTabTitle(tab)->x());
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc index 3edcc57d..cb1da97a 100644 --- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc +++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc
@@ -8,8 +8,6 @@ #include "build/build_config.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h" #include "chrome/browser/ui/webui/metrics_handler.h" #include "chrome/common/pref_names.h" @@ -59,9 +57,6 @@ IDS_LOCAL_DISCOVERY_ADDING_PRINTER_MESSAGE2); source->AddLocalizedString("addingDeviceMessage1", IDS_LOCAL_DISCOVERY_ADDING_DEVICE_MESSAGE1); - source->AddLocalizedString("addingDeviceConfirmCodeMessage", - IDS_LOCAL_DISCOVERY_CONFIRM_CODE_MESSAGE); - source->AddLocalizedString("confirmCode", IDS_LOCAL_DISCOVERY_CONFIRM_CODE); source->AddLocalizedString("devicesTitle", IDS_LOCAL_DISCOVERY_DEVICES_PAGE_TITLE); source->AddLocalizedString("noDescriptionDevice", @@ -96,7 +91,6 @@ IDS_LOCAL_DISCOVERY_AVAILABLE_DEVICES); source->AddLocalizedString("myDevicesTitle", IDS_LOCAL_DISCOVERY_MY_DEVICES); - source->AddLocalizedString("backButton", IDS_SETTINGS_TITLE); // Cloud print connector-related strings. #if BUILDFLAG(ENABLE_PRINT_PREVIEW) && !defined(OS_CHROMEOS) @@ -125,11 +119,6 @@ : WebUIController(web_ui) { // Set up the chrome://devices/ source. content::WebUIDataSource* source = CreateLocalDiscoveryHTMLSource(); - Browser* browser = - chrome::FindBrowserWithWebContents(web_ui->GetWebContents()); - // Show a back button pointing to Settings if the browser has no location bar. - if (browser && browser->is_trusted_source()) - source->AddString("backButtonURL", chrome::kChromeUISettingsURL); content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source); // TODO(gene): Use LocalDiscoveryUIHandler to send updated to the devices
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc index 1fa7b8a..c408294f 100644 --- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc +++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
@@ -116,9 +116,8 @@ } LocalDiscoveryUIHandler::LocalDiscoveryUIHandler() - : is_visible_(false), - failed_list_count_(0), - succeded_list_count_(0) { + : failed_list_count_(0), succeded_list_count_(0) { + g_num_visible++; } LocalDiscoveryUIHandler::~LocalDiscoveryUIHandler() { @@ -128,7 +127,7 @@ if (identity_manager) identity_manager->RemoveObserver(this); ResetCurrentRegistration(); - SetIsVisible(false); + g_num_visible--; } // static @@ -141,10 +140,6 @@ "start", base::BindRepeating(&LocalDiscoveryUIHandler::HandleStart, base::Unretained(this))); web_ui()->RegisterMessageCallback( - "isVisible", - base::BindRepeating(&LocalDiscoveryUIHandler::HandleIsVisible, - base::Unretained(this))); - web_ui()->RegisterMessageCallback( "registerDevice", base::BindRepeating(&LocalDiscoveryUIHandler::HandleRegisterDevice, base::Unretained(this))); @@ -215,13 +210,6 @@ CheckUserLoggedIn(); } -void LocalDiscoveryUIHandler::HandleIsVisible(const base::ListValue* args) { - bool is_visible = false; - bool rv = args->GetBoolean(0, &is_visible); - DCHECK(rv); - SetIsVisible(is_visible); -} - void LocalDiscoveryUIHandler::HandleRegisterDevice( const base::ListValue* args) { std::string device; @@ -471,14 +459,6 @@ "local_discovery.onRegistrationSuccess", device_value); } -void LocalDiscoveryUIHandler::SetIsVisible(bool visible) { - if (visible == is_visible_) - return; - - g_num_visible += visible ? 1 : -1; - is_visible_ = visible; -} - std::string LocalDiscoveryUIHandler::GetSyncAccount() const { Profile* profile = Profile::FromWebUI(web_ui()); identity::IdentityManager* identity_manager =
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h index 440c646..072beb1 100644 --- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h +++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
@@ -104,9 +104,6 @@ // For when the page is ready to receive device notifications. void HandleStart(const base::ListValue* args); - // For when a visibility change occurs. - void HandleIsVisible(const base::ListValue* args); - // For when a user choice is made. void HandleRegisterDevice(const base::ListValue* args); @@ -137,9 +134,6 @@ // Singal to the web interface that registration has finished. void SendRegisterDone(const std::string& service_name); - // Set the visibility of the page. - void SetIsVisible(bool visible); - // Get the sync account email. std::string GetSyncAccount() const; @@ -196,9 +190,6 @@ // The device lister used to list devices on the local network. std::unique_ptr<cloud_print::PrivetDeviceLister> privet_lister_; - // Whether or not the page is marked as visible. - bool is_visible_; - // List of printers from cloud print. std::unique_ptr<cloud_print::GCDApiFlow> cloud_print_printer_list_; std::vector<cloud_print::CloudPrintPrinterList::Device> cloud_devices_;
diff --git a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc index b80afb6a..1dbcf03 100644 --- a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc +++ b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
@@ -162,8 +162,6 @@ IDR_MD_BOOKMARKS_DIALOG_FOCUS_MANAGER_HTML); source->AddResourcePath("dialog_focus_manager.js", IDR_MD_BOOKMARKS_DIALOG_FOCUS_MANAGER_JS); - source->AddResourcePath("dnd_chip.html", IDR_MD_BOOKMARKS_DND_CHIP_HTML); - source->AddResourcePath("dnd_chip.js", IDR_MD_BOOKMARKS_DND_CHIP_JS); source->AddResourcePath("dnd_manager.html", IDR_MD_BOOKMARKS_DND_MANAGER_HTML); source->AddResourcePath("dnd_manager.js", IDR_MD_BOOKMARKS_DND_MANAGER_JS);
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc index 956a6b38..c8fbaecf 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
@@ -231,6 +231,9 @@ const gfx::Size& page_size, const scoped_refptr<base::RefCountedMemory>& print_data, PrintCallback callback) { + size_t size_in_kb = print_data->size() / 1024; + UMA_HISTOGRAM_MEMORY_KB("Printing.CUPS.PrintDocumentSize", size_in_kb); + printing::StartLocalPrint(ticket_json, print_data, preview_web_contents_, std::move(callback)); }
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 5f0cdc2..6014e45 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -1117,6 +1117,10 @@ IDS_SETTINGS_EASY_UNLOCK_PROXIMITY_THRESHOLD_FAR}, {"easyUnlockProximityThresholdVeryFar", IDS_SETTINGS_EASY_UNLOCK_PROXIMITY_THRESHOLD_VERY_FAR}, + {"easyUnlockUnlockDeviceOnly", + IDS_SETTINGS_EASY_UNLOCK_UNLOCK_DEVICE_ONLY}, + {"easyUnlockUnlockDeviceAndAllowSignin", + IDS_SETTINGS_EASY_UNLOCK_UNLOCK_DEVICE_AND_ALLOW_SIGNIN}, }; AddLocalizedStringsBulk(html_source, localized_strings, arraysize(localized_strings)); @@ -2663,6 +2667,8 @@ IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE_EXPLANATION}, {"multideviceForgetDeviceDialogMessage", IDS_SETTINGS_MULTIDEVICE_FORGET_DEVICE_DIALOG_MESSAGE}, + {"multideviceSmartLockOptions", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_OPTIONS_LOCK}, }; AddLocalizedStringsBulk(html_source, localized_strings, arraysize(localized_strings));
diff --git a/chrome/browser/ui/webui/welcome/welcome_ui.cc b/chrome/browser/ui/webui/welcome/welcome_ui.cc index 53ae802..a07f37c 100644 --- a/chrome/browser/ui/webui/welcome/welcome_ui.cc +++ b/chrome/browser/ui/webui/welcome/welcome_ui.cc
@@ -148,6 +148,9 @@ // apps experiments end. html_source->AddResourcePath("shared/chooser_shared_css.html", IDR_NUX_CHOOSER_SHARED_CSS); + html_source->AddResourcePath( + "shared/i18n_setup.html", + IDR_WELCOME_ONBOARDING_WELCOME_SHARED_I18N_SETUP_HTML); if (base::FeatureList::IsEnabled(nux::kNuxOnboardingFeature)) { web_ui->AddMessageHandler(std::make_unique<nux::SetAsDefaultHandler>());
diff --git a/chrome/browser/vr/service/browser_xr_runtime.cc b/chrome/browser/vr/service/browser_xr_runtime.cc index 4813c1d..fccecce 100644 --- a/chrome/browser/vr/service/browser_xr_runtime.cc +++ b/chrome/browser/vr/service/browser_xr_runtime.cc
@@ -17,20 +17,21 @@ display_info_(std::move(display_info)), binding_(this), weak_ptr_factory_(this) { - device::mojom::XRRuntimeEventListenerPtr listener; + device::mojom::XRRuntimeEventListenerAssociatedPtr listener; binding_.Bind(mojo::MakeRequest(&listener)); // Unretained is safe because we are calling through an InterfacePtr we own, // so we won't be called after runtime_ is destroyed. runtime_->ListenToDeviceChanges( - std::move(listener), + listener.PassInterface(), base::BindOnce(&BrowserXRRuntime::OnInitialDevicePropertiesReceived, base::Unretained(this))); } void BrowserXRRuntime::OnInitialDevicePropertiesReceived( device::mojom::VRDisplayInfoPtr display_info) { - OnDisplayInfoChanged(std::move(display_info)); + if (!display_info_) + OnDisplayInfoChanged(std::move(display_info)); } BrowserXRRuntime::~BrowserXRRuntime() = default; @@ -79,6 +80,13 @@ } } +void BrowserXRRuntime::OnInitialized() { + for (auto& callback : pending_initialization_callbacks_) { + std::move(callback).Run(display_info_.Clone()); + } + pending_initialization_callbacks_.clear(); +} + void BrowserXRRuntime::OnRendererDeviceAdded(XRDeviceImpl* device) { renderer_device_connections_.insert(device); } @@ -164,6 +172,19 @@ } } +void BrowserXRRuntime::InitializeAndGetDisplayInfo( + device::mojom::XRDevice::GetImmersiveVRDisplayInfoCallback callback) { + device::mojom::VRDisplayInfoPtr device_info = GetVRDisplayInfo(); + if (device_info) { + std::move(callback).Run(std::move(device_info)); + return; + } + + pending_initialization_callbacks_.push_back(std::move(callback)); + runtime_->EnsureInitialized( + base::BindOnce(&BrowserXRRuntime::OnInitialized, base::Unretained(this))); +} + void BrowserXRRuntime::OnListeningForActivate(bool is_listening) { runtime_->SetListeningForActivate(is_listening); }
diff --git a/chrome/browser/vr/service/browser_xr_runtime.h b/chrome/browser/vr/service/browser_xr_runtime.h index 741f5bf..3c402f2 100644 --- a/chrome/browser/vr/service/browser_xr_runtime.h +++ b/chrome/browser/vr/service/browser_xr_runtime.h
@@ -10,7 +10,7 @@ #include "device/vr/public/mojom/isolated_xr_service.mojom.h" #include "device/vr/public/mojom/vr_service.mojom.h" #include "device/vr/vr_device.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/associated_binding.h" namespace content { class WebContents; @@ -56,6 +56,8 @@ device::mojom::VRDisplayInfoPtr GetVRDisplayInfo() { return display_info_.Clone(); } + void InitializeAndGetDisplayInfo( + device::mojom::XRDevice::GetImmersiveVRDisplayInfoCallback callback); // Methods called to support metrics/overlays on Windows. void AddObserver(BrowserXRRuntimeObserver* observer) { @@ -85,6 +87,7 @@ device::mojom::XRSessionPtr session, device::mojom::XRSessionControllerPtr immersive_session_controller); void OnImmersiveSessionError(); + void OnInitialized(); device::mojom::XRRuntimePtr runtime_; device::mojom::XRSessionControllerPtr immersive_session_controller_; @@ -95,7 +98,9 @@ XRDeviceImpl* listening_for_activation_renderer_device_ = nullptr; XRDeviceImpl* presenting_renderer_device_ = nullptr; - mojo::Binding<device::mojom::XRRuntimeEventListener> binding_; + mojo::AssociatedBinding<device::mojom::XRRuntimeEventListener> binding_; + std::vector<device::mojom::XRDevice::GetImmersiveVRDisplayInfoCallback> + pending_initialization_callbacks_; base::ObserverList<BrowserXRRuntimeObserver> observers_;
diff --git a/chrome/browser/vr/service/xr_device_impl.cc b/chrome/browser/vr/service/xr_device_impl.cc index fea8f982..183b25af 100644 --- a/chrome/browser/vr/service/xr_device_impl.cc +++ b/chrome/browser/vr/service/xr_device_impl.cc
@@ -203,9 +203,12 @@ device::mojom::XRDevice::GetImmersiveVRDisplayInfoCallback callback) { BrowserXRRuntime* immersive_runtime = XRRuntimeManager::GetInstance()->GetImmersiveRuntime(); - device::mojom::VRDisplayInfoPtr device_info = - immersive_runtime ? immersive_runtime->GetVRDisplayInfo() : nullptr; - std::move(callback).Run(std::move(device_info)); + if (!immersive_runtime) { + std::move(callback).Run(nullptr); + return; + } + + immersive_runtime->InitializeAndGetDisplayInfo(std::move(callback)); } void XRDeviceImpl::SetInFocusedFrame(bool in_focused_frame) {
diff --git a/chrome/browser/vr/service/xr_runtime_manager.cc b/chrome/browser/vr/service/xr_runtime_manager.cc index 07a9d36..7a25455 100644 --- a/chrome/browser/vr/service/xr_runtime_manager.cc +++ b/chrome/browser/vr/service/xr_runtime_manager.cc
@@ -62,7 +62,7 @@ #if defined(OS_ANDROID) #if BUILDFLAG(ENABLE_ARCORE) if (base::FeatureList::IsEnabled(features::kWebXrHitTest)) { - providers.emplace_back(device::ARCoreDeviceProviderFactory::Create()); + providers.emplace_back(device::ArCoreDeviceProviderFactory::Create()); } #endif @@ -198,6 +198,12 @@ if (immersive_runtime) { // Listen to changes for this device. immersive_runtime->OnRendererDeviceAdded(device); + + // If we don't have display info for the immersive device, get display info + // from a different device. + if (!immersive_runtime->GetVRDisplayInfo()) { + immersive_runtime = nullptr; + } } // Get an AR device if there is one.
diff --git a/chrome/browser/web_applications/components/web_app_data_retriever.cc b/chrome/browser/web_applications/components/web_app_data_retriever.cc index 71fae7c..4b440d6 100644 --- a/chrome/browser/web_applications/components/web_app_data_retriever.cc +++ b/chrome/browser/web_applications/components/web_app_data_retriever.cc
@@ -70,9 +70,8 @@ // Generate missing icons. static constexpr int kIconSizesToGenerate[] = { - web_app::icon_size::k32, web_app::icon_size::k32 * 2, - web_app::icon_size::k48, web_app::icon_size::k48 * 2, - web_app::icon_size::k128, web_app::icon_size::k128 * 2, + icon_size::k32, icon_size::k32 * 2, icon_size::k48, + icon_size::k48 * 2, icon_size::k128, icon_size::k128 * 2, }; // Get the letter to use in the generated icon. @@ -97,7 +96,7 @@ WebApplicationInfo::IconInfo icon_info; icon_info.width = size; icon_info.height = size; - icon_info.data = web_app::GenerateBitmap(size, SK_ColorDKGRAY, icon_letter); + icon_info.data = GenerateBitmap(size, SK_ColorDKGRAY, icon_letter); icons.push_back(icon_info); }
diff --git a/chrome/browser/web_applications/components/web_app_helpers.cc b/chrome/browser/web_applications/components/web_app_helpers.cc index 08205f4..fdfc4fd 100644 --- a/chrome/browser/web_applications/components/web_app_helpers.cc +++ b/chrome/browser/web_applications/components/web_app_helpers.cc
@@ -24,25 +24,25 @@ // are no naming conflicts. static const char kCrxAppPrefix[] = "_crx_"; -std::string GenerateApplicationNameFromAppId(const std::string& app_id) { +std::string GenerateApplicationNameFromAppId(const AppId& app_id) { std::string t(kCrxAppPrefix); t.append(app_id); return t; } -std::string GetAppIdFromApplicationName(const std::string& app_name) { +AppId GetAppIdFromApplicationName(const std::string& app_name) { std::string prefix(kCrxAppPrefix); if (app_name.substr(0, prefix.length()) != prefix) return std::string(); return app_name.substr(prefix.length()); } -static std::string GenerateExtensionHashFromURL(const GURL& url) { +static std::string GenerateAppHashFromURL(const GURL& url) { return crypto::SHA256HashString(url.spec()); } -std::string GenerateExtensionIdFromURL(const GURL& url) { - return crx_file::id_util::GenerateId(GenerateExtensionHashFromURL(url)); +AppId GenerateAppIdFromURL(const GURL& url) { + return crx_file::id_util::GenerateId(GenerateAppHashFromURL(url)); } // Generate the public key for the fake extension that we synthesize to contain @@ -56,9 +56,9 @@ // // (*) The comment above says that we hash the manifest URL, but in practice, // it seems that we hash the start URL. -std::string GenerateExtensionKeyFromURL(const GURL& url) { +std::string GenerateAppKeyFromURL(const GURL& url) { std::string key; - base::Base64Encode(GenerateExtensionHashFromURL(url), &key); + base::Base64Encode(GenerateAppHashFromURL(url), &key); return key; }
diff --git a/chrome/browser/web_applications/components/web_app_helpers.h b/chrome/browser/web_applications/components/web_app_helpers.h index 2abf80f8..29ebf73 100644 --- a/chrome/browser/web_applications/components/web_app_helpers.h +++ b/chrome/browser/web_applications/components/web_app_helpers.h
@@ -11,19 +11,22 @@ namespace web_app { +// App ID matches Extension ID. +using AppId = std::string; + // Compute a deterministic name based on the URL. We use this pseudo name // as a key to store window location per application URLs in Browser and // as app id for BrowserWindow, shortcut and jump list. std::string GenerateApplicationNameFromURL(const GURL& url); // Compute a deterministic name based on an apps's id. -std::string GenerateApplicationNameFromAppId(const std::string& app_id); +std::string GenerateApplicationNameFromAppId(const AppId& app_id); // Extracts the application id from the app name. -std::string GetAppIdFromApplicationName(const std::string& app_name); +AppId GetAppIdFromApplicationName(const std::string& app_name); -// Compute the Extension ID (such as "fedbieoalmbobgfjapopkghdmhgncnaa") or -// Extension Key, from a web app's URL. Both are derived from a hash of the +// Compute the App ID (such as "fedbieoalmbobgfjapopkghdmhgncnaa") or +// App Key, from a web app's URL. Both are derived from a hash of the // URL, but are subsequently encoded differently, for historical reasons. The // ID is a Base-16 encoded (a=0, b=1, ..., p=15) subset of the hash, and is // used as a directory name, sometimes on case-insensitive file systems @@ -32,10 +35,12 @@ // For PWAs (progressive web apps), the URL should be the Start URL, explicitly // listed in the manifest. // -// For non-PWA web apps, also known as "bookmark apps", the URL is just the +// For non-PWA web apps, also known as "shortcuts", the URL is just the // bookmark URL. -std::string GenerateExtensionIdFromURL(const GURL& url); -std::string GenerateExtensionKeyFromURL(const GURL& url); +// +// App ID and App Key match Extension ID and Extension Key for migration. +AppId GenerateAppIdFromURL(const GURL& url); +std::string GenerateAppKeyFromURL(const GURL& url); // Returns whether the given |app_url| is a valid bookmark app url. bool IsValidWebAppUrl(const GURL& app_url);
diff --git a/chrome/browser/web_applications/components/web_app_helpers_unittest.cc b/chrome/browser/web_applications/components/web_app_helpers_unittest.cc index 5211250b..d8cf8ed7 100644 --- a/chrome/browser/web_applications/components/web_app_helpers_unittest.cc +++ b/chrome/browser/web_applications/components/web_app_helpers_unittest.cc
@@ -19,16 +19,16 @@ GenerateApplicationNameFromURL(GURL("https://example.com/path"))); } -TEST(WebAppHelpers, GenerateExtensionIdFromURL) { - EXPECT_EQ("fedbieoalmbobgfjapopkghdmhgncnaa", - GenerateExtensionIdFromURL( - GURL("https://www.chromestatus.com/features"))); +TEST(WebAppHelpers, GenerateAppIdFromURL) { + EXPECT_EQ( + "fedbieoalmbobgfjapopkghdmhgncnaa", + GenerateAppIdFromURL(GURL("https://www.chromestatus.com/features"))); // The io2016 example is also walked through at // https://play.golang.org/p/VrIq_QKFjiV EXPECT_EQ( "mjgafbdfajpigcjmkgmeokfbodbcfijl", - GenerateExtensionIdFromURL(GURL( + GenerateAppIdFromURL(GURL( "https://events.google.com/io2016/?utm_source=web_app_manifest"))); }
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc index 3f61534..6765f82 100644 --- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc +++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
@@ -4,10 +4,15 @@ #include "chrome/browser/web_applications/extensions/web_app_extension_shortcut.h" +#include <utility> +#include <vector> + +#include "base/callback.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/extension_ui_util.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" @@ -16,6 +21,7 @@ #include "content/public/browser/browser_thread.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/image_loader.h" +#include "extensions/common/extension.h" #include "extensions/common/manifest_handlers/icons_handler.h" #include "extensions/grit/extensions_browser_resources.h" #include "skia/ext/image_operations.h" @@ -33,6 +39,8 @@ using content::BrowserThread; +namespace web_app { + namespace { #if defined(OS_MACOSX) @@ -51,8 +59,8 @@ const size_t kNumDesiredSizes = base::size(kDesiredSizes); #endif -void OnImageLoaded(std::unique_ptr<web_app::ShortcutInfo> shortcut_info, - web_app::ShortcutInfoCallback callback, +void OnImageLoaded(std::unique_ptr<ShortcutInfo> shortcut_info, + ShortcutInfoCallback callback, gfx::ImageFamily image_family) { // If the image failed to load (e.g. if the resource being loaded was empty) // use the standard application icon. @@ -79,32 +87,29 @@ void UpdateAllShortcutsForShortcutInfo( const base::string16& old_app_title, base::OnceClosure callback, - std::unique_ptr<web_app::ShortcutInfo> shortcut_info) { + std::unique_ptr<ShortcutInfo> shortcut_info) { base::FilePath shortcut_data_dir = - web_app::internals::GetShortcutDataDir(*shortcut_info); - web_app::internals::PostShortcutIOTaskAndReply( - base::BindOnce(&web_app::internals::UpdatePlatformShortcuts, - shortcut_data_dir, old_app_title), + internals::GetShortcutDataDir(*shortcut_info); + internals::PostShortcutIOTaskAndReply( + base::BindOnce(&internals::UpdatePlatformShortcuts, shortcut_data_dir, + old_app_title), std::move(shortcut_info), std::move(callback)); } void ScheduleCreatePlatformShortcut( - web_app::ShortcutCreationReason reason, - const web_app::ShortcutLocations& locations, - std::unique_ptr<web_app::ShortcutInfo> shortcut_info) { + ShortcutCreationReason reason, + const ShortcutLocations& locations, + std::unique_ptr<ShortcutInfo> shortcut_info) { base::FilePath shortcut_data_dir = - web_app::internals::GetShortcutDataDir(*shortcut_info); - web_app::internals::PostShortcutIOTask( - base::BindOnce( - base::IgnoreResult(&web_app::internals::CreatePlatformShortcuts), - shortcut_data_dir, locations, reason), + internals::GetShortcutDataDir(*shortcut_info); + internals::PostShortcutIOTask( + base::BindOnce(base::IgnoreResult(&internals::CreatePlatformShortcuts), + shortcut_data_dir, locations, reason), std::move(shortcut_info)); } } // namespace -namespace web_app { - void CreateShortcutsWithInfo(ShortcutCreationReason reason, const ShortcutLocations& locations, std::unique_ptr<ShortcutInfo> shortcut_info) { @@ -139,8 +144,8 @@ void GetShortcutInfoForApp(const extensions::Extension* extension, Profile* profile, ShortcutInfoCallback callback) { - std::unique_ptr<web_app::ShortcutInfo> shortcut_info( - web_app::ShortcutInfoForExtensionAndProfile(extension, profile)); + std::unique_ptr<ShortcutInfo> shortcut_info( + ShortcutInfoForExtensionAndProfile(extension, profile)); std::vector<extensions::ImageLoader::ImageRepresentation> info_list; for (size_t i = 0; i < kNumDesiredSizes; ++i) { @@ -207,7 +212,7 @@ return shortcut_info; } -bool ShouldCreateShortcutFor(web_app::ShortcutCreationReason reason, +bool ShouldCreateShortcutFor(ShortcutCreationReason reason, Profile* profile, const extensions::Extension* extension) { // Shortcuts should never be created for component apps, or for apps that @@ -278,7 +283,7 @@ std::unique_ptr<ShortcutInfo> shortcut_info( ShortcutInfoForExtensionAndProfile(app, profile)); base::FilePath shortcut_data_dir = - web_app::internals::GetShortcutDataDir(*shortcut_info); + internals::GetShortcutDataDir(*shortcut_info); internals::PostShortcutIOTask( base::BindOnce(&internals::DeletePlatformShortcuts, shortcut_data_dir), std::move(shortcut_info)); @@ -305,7 +310,7 @@ void UpdateRelaunchDetailsForApp(Profile* profile, const extensions::Extension* extension, HWND hwnd) { - web_app::GetShortcutInfoForApp( + GetShortcutInfoForApp( extension, profile, base::BindOnce(&internals::OnShortcutInfoLoadedForSetRelaunchDetails, hwnd));
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.h b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.h index 5dcf41b..21b636b 100644 --- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.h +++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.h
@@ -5,9 +5,13 @@ #ifndef CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_WEB_APP_EXTENSION_SHORTCUT_H_ #define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_WEB_APP_EXTENSION_SHORTCUT_H_ -#include "chrome/browser/web_applications/components/web_app_shortcut.h" +#include <memory> +#include "base/callback_forward.h" +#include "base/files/file_path.h" +#include "base/strings/string16.h" #include "build/build_config.h" +#include "chrome/browser/web_applications/components/web_app_shortcut.h" class Profile; @@ -39,7 +43,7 @@ Profile* profile); // Whether to create a shortcut for this type of extension. -bool ShouldCreateShortcutFor(web_app::ShortcutCreationReason reason, +bool ShouldCreateShortcutFor(ShortcutCreationReason reason, Profile* profile, const extensions::Extension* extension); @@ -75,22 +79,11 @@ void UpdateShortcutsForAllApps(Profile* profile, base::OnceClosure callback); #if defined(OS_WIN) - // Update the relaunch details for the given app's window, making the taskbar // group's "Pin to the taskbar" button function correctly. void UpdateRelaunchDetailsForApp(Profile* profile, const extensions::Extension* extension, HWND hwnd); - -namespace internals { - -// Returns the Windows user-level shortcut paths that are specified in -// |creation_locations|. -std::vector<base::FilePath> GetShortcutPaths( - const ShortcutLocations& creation_locations); - -} // namespace internals - #endif // defined(OS_WIN) } // namespace web_app
diff --git a/chrome/common/apps/platform_apps/BUILD.gn b/chrome/common/apps/platform_apps/BUILD.gn index b8ddfa0..f94a5b2 100644 --- a/chrome/common/apps/platform_apps/BUILD.gn +++ b/chrome/common/apps/platform_apps/BUILD.gn
@@ -13,6 +13,13 @@ "chrome_apps_api_permissions.h", "chrome_apps_api_provider.cc", "chrome_apps_api_provider.h", + "chrome_apps_message_generator.cc", + "chrome_apps_message_generator.h", + "chrome_apps_messages.h", + "media_galleries_permission.cc", + "media_galleries_permission.h", + "media_galleries_permission_data.cc", + "media_galleries_permission_data.h", ] deps = [ @@ -20,5 +27,6 @@ "//chrome/common/apps/platform_apps/api", "//chrome/common/apps/platform_apps/api:apps_features", "//extensions/common", + "//ipc", ] }
diff --git a/chrome/common/apps/platform_apps/OWNERS b/chrome/common/apps/platform_apps/OWNERS new file mode 100644 index 0000000..42444bc --- /dev/null +++ b/chrome/common/apps/platform_apps/OWNERS
@@ -0,0 +1,2 @@ +per-file *_messages*.h=set noparent +per-file *_messages*.h=file://ipc/SECURITY_OWNERS
diff --git a/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc b/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc index 9380f85b..fcf51395 100644 --- a/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc +++ b/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc
@@ -4,7 +4,7 @@ #include "chrome/common/apps/platform_apps/chrome_apps_api_permissions.h" -#include "extensions/common/permissions/media_galleries_permission.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" namespace chrome_apps_api_permissions { namespace { @@ -25,7 +25,7 @@ extensions::APIPermissionInfo::kFlagCannotBeOptional}, {extensions::APIPermission::kMediaGalleries, "mediaGalleries", extensions::APIPermissionInfo::kFlagNone, - &CreateAPIPermission<extensions::MediaGalleriesPermission>}, + &CreateAPIPermission<chrome_apps::MediaGalleriesPermission>}, }; } // namespace
diff --git a/chrome/common/apps/platform_apps/chrome_apps_message_generator.cc b/chrome/common/apps/platform_apps/chrome_apps_message_generator.cc new file mode 100644 index 0000000..bbfda936 --- /dev/null +++ b/chrome/common/apps/platform_apps/chrome_apps_message_generator.cc
@@ -0,0 +1,34 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Get basic type definitions. +#define IPC_MESSAGE_IMPL +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" + +// Generate constructors. +#include "ipc/struct_constructor_macros.h" +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" + +// Generate destructors. +#include "ipc/struct_destructor_macros.h" +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" + +// Generate param traits write methods. +#include "ipc/param_traits_write_macros.h" +namespace IPC { +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" +} // namespace IPC + +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" +} // namespace IPC + +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h" +} // namespace IPC +
diff --git a/chrome/common/apps/platform_apps/chrome_apps_message_generator.h b/chrome/common/apps/platform_apps/chrome_apps_message_generator.h new file mode 100644 index 0000000..1903b73 --- /dev/null +++ b/chrome/common/apps/platform_apps/chrome_apps_message_generator.h
@@ -0,0 +1,11 @@ +// 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. + +// Multiply-included file, hence no include guard. + +#undef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_ +#include "chrome/common/apps/platform_apps/chrome_apps_messages.h" +#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_ +#error "Failed to include header chrome/common/apps/platform_apps/chrome_apps_messages.h" +#endif
diff --git a/chrome/common/apps/platform_apps/chrome_apps_messages.h b/chrome/common/apps/platform_apps/chrome_apps_messages.h new file mode 100644 index 0000000..3169f24 --- /dev/null +++ b/chrome/common/apps/platform_apps/chrome_apps_messages.h
@@ -0,0 +1,17 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_ +#define CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_ + +#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h" +#include "ipc/ipc_message_macros.h" + +#define IPC_MESSAGE_START ChromeAppsMsgStart + +IPC_STRUCT_TRAITS_BEGIN(chrome_apps::MediaGalleriesPermissionData) + IPC_STRUCT_TRAITS_MEMBER(permission()) +IPC_STRUCT_TRAITS_END() + +#endif // CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_
diff --git a/extensions/common/permissions/media_galleries_permission.cc b/chrome/common/apps/platform_apps/media_galleries_permission.cc similarity index 77% rename from extensions/common/permissions/media_galleries_permission.cc rename to chrome/common/apps/platform_apps/media_galleries_permission.cc index 10fb24c..621bb130 100644 --- a/extensions/common/permissions/media_galleries_permission.cc +++ b/chrome/common/apps/platform_apps/media_galleries_permission.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 "extensions/common/permissions/media_galleries_permission.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" #include <stddef.h> @@ -12,16 +12,17 @@ #include "base/logging.h" #include "base/strings/utf_string_conversions.h" #include "extensions/common/permissions/permissions_info.h" -#include "extensions/strings/grit/extensions_strings.h" #include "ui/base/l10n/l10n_util.h" -namespace extensions { +namespace chrome_apps { namespace { // copyTo permission requires delete permission as a prerequisite. // delete permission requires read permission as a prerequisite. -bool IsValidPermissionSet(bool has_read, bool has_copy_to, bool has_delete, +bool IsValidPermissionSet(bool has_read, + bool has_copy_to, + bool has_delete, std::string* error) { if (has_copy_to) { if (has_read && has_delete) @@ -49,13 +50,11 @@ const char MediaGalleriesPermission::kDeletePermission[] = "delete"; MediaGalleriesPermission::MediaGalleriesPermission( - const APIPermissionInfo* info) - : SetDisjunctionPermission<MediaGalleriesPermissionData, - MediaGalleriesPermission>(info) { -} + const extensions::APIPermissionInfo* info) + : SetDisjunctionPermission<MediaGalleriesPermissionData, + MediaGalleriesPermission>(info) {} -MediaGalleriesPermission::~MediaGalleriesPermission() { -} +MediaGalleriesPermission::~MediaGalleriesPermission() {} bool MediaGalleriesPermission::FromValue( const base::Value* value, @@ -64,14 +63,12 @@ size_t unhandled_permissions_count = 0; if (unhandled_permissions) unhandled_permissions_count = unhandled_permissions->size(); - bool parsed_ok = - SetDisjunctionPermission<MediaGalleriesPermissionData, - MediaGalleriesPermission>::FromValue( - value, error, unhandled_permissions); + bool parsed_ok = SetDisjunctionPermission< + MediaGalleriesPermissionData, + MediaGalleriesPermission>::FromValue(value, error, unhandled_permissions); if (unhandled_permissions) { for (size_t i = unhandled_permissions_count; - i < unhandled_permissions->size(); - i++) { + i < unhandled_permissions->size(); i++) { (*unhandled_permissions)[i] = "{\"mediaGalleries\": [" + (*unhandled_permissions)[i] + "]}"; } @@ -83,7 +80,8 @@ bool has_copy_to = false; bool has_delete = false; for (std::set<MediaGalleriesPermissionData>::const_iterator it = - data_set_.begin(); it != data_set_.end(); ++it) { + data_set_.begin(); + it != data_set_.end(); ++it) { if (it->permission() == kAllAutoDetectedPermission) { continue; } @@ -110,8 +108,8 @@ return IsValidPermissionSet(has_read, has_copy_to, has_delete, error); } -PermissionIDSet MediaGalleriesPermission::GetPermissions() const { - PermissionIDSet result; +extensions::PermissionIDSet MediaGalleriesPermission::GetPermissions() const { + extensions::PermissionIDSet result; bool has_all_auto_detected = false; bool has_read = false; @@ -144,18 +142,18 @@ // Separate PermissionMessage IDs for read, copyTo, and delete. Otherwise an // extension can silently gain new access capabilities. - result.insert(APIPermission::kMediaGalleriesAllGalleriesRead); + result.insert(extensions::APIPermission::kMediaGalleriesAllGalleriesRead); // For copyTo and delete, the proper combined permission message will be // derived in ChromePermissionMessageProvider::GetWarningMessages(), such // that the user get 1 entry for all media galleries access permissions, // rather than several separate entries. if (has_copy_to) - result.insert(APIPermission::kMediaGalleriesAllGalleriesCopyTo); + result.insert(extensions::APIPermission::kMediaGalleriesAllGalleriesCopyTo); if (has_delete) - result.insert(APIPermission::kMediaGalleriesAllGalleriesDelete); + result.insert(extensions::APIPermission::kMediaGalleriesAllGalleriesDelete); return result; } -} // namespace extensions +} // namespace chrome_apps
diff --git a/extensions/common/permissions/media_galleries_permission.h b/chrome/common/apps/platform_apps/media_galleries_permission.h similarity index 67% rename from extensions/common/permissions/media_galleries_permission.h rename to chrome/common/apps/platform_apps/media_galleries_permission.h index 706cd5ba..c5792fda 100644 --- a/extensions/common/permissions/media_galleries_permission.h +++ b/chrome/common/apps/platform_apps/media_galleries_permission.h
@@ -2,14 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef EXTENSIONS_COMMON_PERMISSIONS_MEDIA_GALLERIES_PERMISSION_H_ -#define EXTENSIONS_COMMON_PERMISSIONS_MEDIA_GALLERIES_PERMISSION_H_ +#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_H_ +#define CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_H_ +#include "chrome/common/apps/platform_apps/chrome_apps_messages.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h" #include "extensions/common/permissions/api_permission.h" -#include "extensions/common/permissions/media_galleries_permission_data.h" #include "extensions/common/permissions/set_disjunction_permission.h" -namespace extensions { +namespace chrome_apps { // Media Galleries permissions are as follows: // <media-galleries-permission-pattern> @@ -27,16 +28,16 @@ // "mediaGalleries", // TODO(devlin): Move this class to chrome/common/apps/platform_apps. class MediaGalleriesPermission - : public SetDisjunctionPermission<MediaGalleriesPermissionData, - MediaGalleriesPermission> { + : public extensions::SetDisjunctionPermission<MediaGalleriesPermissionData, + MediaGalleriesPermission> { public: - struct CheckParam : public APIPermission::CheckParam { + struct CheckParam : public extensions::APIPermission::CheckParam { explicit CheckParam(const std::string& permission) - : permission(permission) {} + : permission(permission) {} const std::string permission; }; - explicit MediaGalleriesPermission(const APIPermissionInfo* info); + explicit MediaGalleriesPermission(const extensions::APIPermissionInfo* info); ~MediaGalleriesPermission() override; // SetDisjunctionPermission overrides. @@ -46,8 +47,8 @@ std::string* error, std::vector<std::string>* unhandled_permissions) override; - // APIPermission overrides. - PermissionIDSet GetPermissions() const override; + // extensions::APIPermission overrides. + extensions::PermissionIDSet GetPermissions() const override; // Permission strings. static const char kAllAutoDetectedPermission[]; @@ -57,6 +58,6 @@ static const char kDeletePermission[]; }; -} // namespace extensions +} // namespace chrome_apps -#endif // EXTENSIONS_COMMON_PERMISSIONS_MEDIA_GALLERIES_PERMISSION_H_ +#endif // CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_H_
diff --git a/extensions/common/permissions/media_galleries_permission_data.cc b/chrome/common/apps/platform_apps/media_galleries_permission_data.cc similarity index 79% rename from extensions/common/permissions/media_galleries_permission_data.cc rename to chrome/common/apps/platform_apps/media_galleries_permission_data.cc index 330923d..148abba 100644 --- a/extensions/common/permissions/media_galleries_permission_data.cc +++ b/chrome/common/apps/platform_apps/media_galleries_permission_data.cc
@@ -2,19 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "extensions/common/permissions/media_galleries_permission_data.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h" #include "base/strings/string_util.h" #include "base/values.h" -#include "extensions/common/permissions/media_galleries_permission.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" -namespace extensions { +namespace chrome_apps { -MediaGalleriesPermissionData::MediaGalleriesPermissionData() { -} +MediaGalleriesPermissionData::MediaGalleriesPermissionData() {} bool MediaGalleriesPermissionData::Check( - const APIPermission::CheckParam* param) const { + const extensions::APIPermission::CheckParam* param) const { if (!param) return false; @@ -24,7 +23,7 @@ } std::unique_ptr<base::Value> MediaGalleriesPermissionData::ToValue() const { - return std::unique_ptr<base::Value>(new base::Value(permission_)); + return std::make_unique<base::Value>(permission_); } bool MediaGalleriesPermissionData::FromValue(const base::Value* value) { @@ -58,4 +57,4 @@ return permission_ == rhs.permission_; } -} // namespace extensions +} // namespace chrome_apps
diff --git a/extensions/common/permissions/media_galleries_permission_data.h b/chrome/common/apps/platform_apps/media_galleries_permission_data.h similarity index 77% rename from extensions/common/permissions/media_galleries_permission_data.h rename to chrome/common/apps/platform_apps/media_galleries_permission_data.h index db8df839..495cb48d 100644 --- a/extensions/common/permissions/media_galleries_permission_data.h +++ b/chrome/common/apps/platform_apps/media_galleries_permission_data.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 EXTENSIONS_COMMON_PERMISSIONS_MEDIA_GALLERIES_PERMISSION_DATA_H_ -#define EXTENSIONS_COMMON_PERMISSIONS_MEDIA_GALLERIES_PERMISSION_DATA_H_ +#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_DATA_H_ +#define CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_DATA_H_ #include <memory> #include <string> @@ -14,7 +14,7 @@ class Value; } -namespace extensions { +namespace chrome_apps { // A MediaGalleriesPermissionData instance represents a single part of the // MediaGalleriesPermission. e.g. "read" or "allAutoDetected". @@ -24,7 +24,7 @@ // Check if |param| (which must be a MediaGalleriesPermission::CheckParam) // matches the encapsulated attribute. - bool Check(const APIPermission::CheckParam* param) const; + bool Check(const extensions::APIPermission::CheckParam* param) const; // Convert |this| into a base::Value. std::unique_ptr<base::Value> ToValue() const; @@ -45,6 +45,6 @@ std::string permission_; }; -} // namespace extensions +} // namespace chrome_apps -#endif // EXTENSIONS_COMMON_PERMISSIONS_MEDIA_GALLERIES_PERMISSION_DATA_H_ +#endif // CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_DATA_H_
diff --git a/chrome/common/extensions/permissions/media_galleries_permission_unittest.cc b/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc similarity index 85% rename from chrome/common/extensions/permissions/media_galleries_permission_unittest.cc rename to chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc index 15c29bc..d8fbc24 100644 --- a/chrome/common/extensions/permissions/media_galleries_permission_unittest.cc +++ b/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc
@@ -7,20 +7,21 @@ #include <memory> #include "base/values.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission.h" +#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h" #include "extensions/common/permissions/api_permission.h" -#include "extensions/common/permissions/media_galleries_permission.h" -#include "extensions/common/permissions/media_galleries_permission_data.h" #include "extensions/common/permissions/permissions_info.h" #include "testing/gtest/include/gtest/gtest.h" using content::SocketPermissionRequest; using extensions::SocketPermissionData; -namespace extensions { +namespace chrome_apps { namespace { -void CheckFromValue(APIPermission* permission, base::ListValue* value, +void CheckFromValue(extensions::APIPermission* permission, + base::ListValue* value, bool success_expected) { std::string error; std::vector<std::string> unhandled; @@ -30,10 +31,11 @@ } TEST(MediaGalleriesPermissionTest, GoodValues) { - const APIPermissionInfo* permission_info = - PermissionsInfo::GetInstance()->GetByID(APIPermission::kMediaGalleries); + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); - std::unique_ptr<APIPermission> permission( + std::unique_ptr<extensions::APIPermission> permission( permission_info->CreateAPIPermission()); // access_type + all_detected @@ -87,10 +89,11 @@ } TEST(MediaGalleriesPermissionTest, BadValues) { - const APIPermissionInfo* permission_info = - PermissionsInfo::GetInstance()->GetByID(APIPermission::kMediaGalleries); + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); - std::unique_ptr<APIPermission> permission( + std::unique_ptr<extensions::APIPermission> permission( permission_info->CreateAPIPermission()); // copyTo and delete without read @@ -133,10 +136,11 @@ TEST(MediaGalleriesPermissionTest, UnknownValues) { std::string error; std::vector<std::string> unhandled; - const APIPermissionInfo* permission_info = - PermissionsInfo::GetInstance()->GetByID(APIPermission::kMediaGalleries); + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); - std::unique_ptr<APIPermission> permission( + std::unique_ptr<extensions::APIPermission> permission( permission_info->CreateAPIPermission()); // A good one and an unknown one. @@ -168,12 +172,13 @@ } TEST(MediaGalleriesPermissionTest, Equal) { - const APIPermissionInfo* permission_info = - PermissionsInfo::GetInstance()->GetByID(APIPermission::kMediaGalleries); + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); - std::unique_ptr<APIPermission> permission1( + std::unique_ptr<extensions::APIPermission> permission1( permission_info->CreateAPIPermission()); - std::unique_ptr<APIPermission> permission2( + std::unique_ptr<extensions::APIPermission> permission2( permission_info->CreateAPIPermission()); std::unique_ptr<base::ListValue> value(new base::ListValue()); @@ -220,12 +225,13 @@ } TEST(MediaGalleriesPermissionTest, NotEqual) { - const APIPermissionInfo* permission_info = - PermissionsInfo::GetInstance()->GetByID(APIPermission::kMediaGalleries); + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); - std::unique_ptr<APIPermission> permission1( + std::unique_ptr<extensions::APIPermission> permission1( permission_info->CreateAPIPermission()); - std::unique_ptr<APIPermission> permission2( + std::unique_ptr<extensions::APIPermission> permission2( permission_info->CreateAPIPermission()); std::unique_ptr<base::ListValue> value(new base::ListValue()); @@ -243,12 +249,13 @@ } TEST(MediaGalleriesPermissionTest, ToFromValue) { - const APIPermissionInfo* permission_info = - PermissionsInfo::GetInstance()->GetByID(APIPermission::kMediaGalleries); + const extensions::APIPermissionInfo* permission_info = + extensions::PermissionsInfo::GetInstance()->GetByID( + extensions::APIPermission::kMediaGalleries); - std::unique_ptr<APIPermission> permission1( + std::unique_ptr<extensions::APIPermission> permission1( permission_info->CreateAPIPermission()); - std::unique_ptr<APIPermission> permission2( + std::unique_ptr<extensions::APIPermission> permission2( permission_info->CreateAPIPermission()); std::unique_ptr<base::ListValue> value(new base::ListValue()); @@ -294,4 +301,4 @@ } // namespace -} // namespace extensions +} // namespace chrome_apps
diff --git a/chrome/common/available_offline_content.mojom b/chrome/common/available_offline_content.mojom index 2bf374d..f6ac36e 100644 --- a/chrome/common/available_offline_content.mojom +++ b/chrome/common/available_offline_content.mojom
@@ -68,5 +68,5 @@ // Opens one of the items returned by List(). LaunchItem(string item_id, string name_space); // Opens the downloads page to view all offline content. - LaunchDownloadsPage(); + LaunchDownloadsPage(bool open_prefetched_articles_tab); };
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index e8099d1..e065d53e 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -138,6 +138,12 @@ base::FEATURE_ENABLED_BY_DEFAULT}; #endif +#if defined(OS_MACOSX) +// Enables the suggested text touch bar for autocomplete in textfields. +const base::Feature kTextSuggestionsTouchBar{"TextSuggestionsTouchBar", + base::FEATURE_DISABLED_BY_DEFAULT}; +#endif + #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) // Enables the blocking of third-party modules. // Note: Due to a limitation in the implementation of this feature, it is @@ -206,6 +212,10 @@ const base::Feature kDesktopPWAsLinkCapturing{ "DesktopPWAsLinkCapturing", base::FEATURE_DISABLED_BY_DEFAULT}; +// Determines whether in scope requests are always opened in the same window. +const base::Feature kDesktopPWAsStayInWindow{"DesktopPWAsStayInWindow", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Disables downloads of unsafe file types over HTTP. const base::Feature kDisallowUnsafeHttpDownloads{ "DisallowUnsafeHttpDownloads", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 94821af..ab785e67 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -131,6 +131,9 @@ extern const base::Feature kDesktopPWAsLinkCapturing; COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kDesktopPWAsStayInWindow; + +COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kDisallowUnsafeHttpDownloads; COMPONENT_EXPORT(CHROME_FEATURES) extern const char kDisallowUnsafeHttpDownloadsParamName[]; @@ -371,6 +374,11 @@ COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kTabMetricsLogging; #endif +#if defined(OS_MACOSX) +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kTextSuggestionsTouchBar; +#endif + #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kThirdPartyModulesBlocking;
diff --git a/chrome/common/extensions/api/bookmark_manager_private.json b/chrome/common/extensions/api/bookmark_manager_private.json index 526b4e09..c65c190 100644 --- a/chrome/common/extensions/api/bookmark_manager_private.json +++ b/chrome/common/extensions/api/bookmark_manager_private.json
@@ -149,6 +149,12 @@ "minItems": 1 }, { + "name": "dragNodeIndex", + "type": "integer", + "minimum": 0, + "description": "The index of the dragged node in |idList|" + }, + { "name": "isFromTouch", "type": "boolean", "description": "True if the drag was initiated from touch."
diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl index 836318c..a63582e 100644 --- a/chrome/common/extensions/api/developer_private.idl +++ b/chrome/common/extensions/api/developer_private.idl
@@ -194,16 +194,31 @@ DOMString[] submessages; }; + dictionary SiteControl { + // The host pattern for the site. + DOMString host; + // Whether the pattern has been granted. + boolean granted; + }; + + dictionary SpecificSiteControls { + // True if |hosts| contains an all hosts like pattern. + boolean hasAllHosts; + + // The site controls for all granted and requested patterns. + SiteControl[] hosts; + }; + dictionary Permissions { Permission[] simplePermissions; - // Only populated for extensions affected by the runtime host - // permissions feature. + // Only populated for extensions that can be affected by the runtime host + // permissions feature.The current host access. HostAccess? hostAccess; // Only populated for extensions affected by the runtime host // permissions feature and |hostAccess| is equal to ON_SPECIFIC_SITES. - DOMString[]? runtimeHostPermissions; + SpecificSiteControls? specificSiteControls; }; dictionary ExtensionInfo {
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index ffa1d20..42d769d 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -1704,7 +1704,7 @@ std::string* console_message) { *console_message = base::StringPrintf( "The SSL certificate used to load resources from %s" - " will be distrusted in M70. Once distrusted, users will be prevented" + " will be distrusted very soon. Once distrusted, users will be prevented" " from loading these resources. See https://g.co/chrome/symantecpkicerts" " for more information.", url::Origin::Create(url).Serialize().c_str());
diff --git a/chrome/renderer/net/available_offline_content_helper.cc b/chrome/renderer/net/available_offline_content_helper.cc index 304b31df..d918e1d9 100644 --- a/chrome/renderer/net/available_offline_content_helper.cc +++ b/chrome/renderer/net/available_offline_content_helper.cc
@@ -19,6 +19,7 @@ namespace { using chrome::mojom::AvailableOfflineContentPtr; +using chrome::mojom::AvailableContentType; base::Value AvailableContentToValue(const AvailableOfflineContentPtr& content) { base::Value value(base::Value::Type::DICTIONARY); @@ -111,13 +112,12 @@ if (!BindProvider()) return; - provider_->LaunchItem(id, name_space); - for (const AvailableOfflineContentPtr& item : fetched_content_) { if (item->id == id && item->name_space == name_space) { UMA_HISTOGRAM_ENUMERATION("Net.ErrorPageCounts.SuggestionClicked", item->content_type); RecordEvent(error_page::NETWORK_ERROR_PAGE_OFFLINE_SUGGESTION_CLICKED); + provider_->LaunchItem(id, name_space); return; } } @@ -128,16 +128,22 @@ if (!BindProvider()) return; RecordEvent(error_page::NETWORK_ERROR_PAGE_OFFLINE_DOWNLOADS_PAGE_CLICKED); - provider_->LaunchDownloadsPage(); + provider_->LaunchDownloadsPage(has_prefetched_content_); } void AvailableOfflineContentHelper::AvailableContentReceived( base::OnceCallback<void(const std::string& offline_content_json)> callback, std::vector<AvailableOfflineContentPtr> content) { + has_prefetched_content_ = false; fetched_content_ = std::move(content); std::string json; if (!fetched_content_.empty()) { + // As prefetched content has the highest priority if at least one piece is + // available it will be the at the first position on the list. + has_prefetched_content_ = fetched_content_.front()->content_type == + AvailableContentType::kPrefetchedPage; + RecordSuggestionPresented(fetched_content_); RecordEvent(error_page::NETWORK_ERROR_PAGE_OFFLINE_SUGGESTIONS_SHOWN); base::JSONWriter::Write(AvailableContentListToValue(fetched_content_), @@ -153,9 +159,12 @@ void AvailableOfflineContentHelper::SummaryReceived( base::OnceCallback<void(const std::string& content_summary_json)> callback, chrome::mojom::AvailableOfflineContentSummaryPtr summary) { + has_prefetched_content_ = false; if (summary->total_items == 0) { std::move(callback).Run(""); } else { + has_prefetched_content_ = summary->has_prefetched_page; + std::string json; base::JSONWriter::Write(AvailableContentSummaryToValue(summary), &json); RecordEvent(error_page::NETWORK_ERROR_PAGE_OFFLINE_CONTENT_SUMMARY_SHOWN);
diff --git a/chrome/renderer/net/available_offline_content_helper.h b/chrome/renderer/net/available_offline_content_helper.h index 18335e06..bfa2855c 100644 --- a/chrome/renderer/net/available_offline_content_helper.h +++ b/chrome/renderer/net/available_offline_content_helper.h
@@ -65,6 +65,10 @@ // only so that metrics can be recorded properly on call to LaunchItem(). std::vector<chrome::mojom::AvailableOfflineContentPtr> fetched_content_; + // Records if the last received content message indicated that prefetched + // articles are available or not. + bool has_prefetched_content_ = false; + DISALLOW_COPY_AND_ASSIGN(AvailableOfflineContentHelper); };
diff --git a/chrome/renderer/net/net_error_helper_core_unittest.cc b/chrome/renderer/net/net_error_helper_core_unittest.cc index 82de7af0..cebdac45 100644 --- a/chrome/renderer/net/net_error_helper_core_unittest.cc +++ b/chrome/renderer/net/net_error_helper_core_unittest.cc
@@ -2670,7 +2670,7 @@ MOCK_METHOD2(LaunchItem, void(const std::string& item_ID, const std::string& name_space)); - MOCK_METHOD0(LaunchDownloadsPage, void()); + MOCK_METHOD1(LaunchDownloadsPage, void(bool open_prefetched_articles_tab)); void AddBinding(mojo::ScopedMessagePipeHandle handle) { bindings_.AddBinding(this,
diff --git a/chrome/services/isolated_xr_device/BUILD.gn b/chrome/services/isolated_xr_device/BUILD.gn index ad93a68..f8ed241 100644 --- a/chrome/services/isolated_xr_device/BUILD.gn +++ b/chrome/services/isolated_xr_device/BUILD.gn
@@ -19,6 +19,7 @@ deps = [ "//base", + "//chrome/common", "//device/vr:vr", "//device/vr/public/mojom", "//device/vr/public/mojom:test_mojom",
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 54b519f9..03a8523 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1968,6 +1968,7 @@ "../browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm", "../browser/ui/cocoa/ssl_client_certificate_selector_cocoa_browsertest.mm", "../browser/ui/cocoa/touchbar/browser_window_touch_bar_controller_browsertest.mm", + "../browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm", ## TODO(crbug/845389): Re-Enable the following, which were temporarily ## omitted from the build, but still in use by the Cocoa browser. @@ -2318,6 +2319,7 @@ "../browser/android/explore_sites/get_catalog_task_unittest.cc", "../browser/android/explore_sites/get_images_task_unittest.cc", "../browser/android/explore_sites/history_statistics_reporter_unittest.cc", + "../browser/android/explore_sites/image_helper_unittest.cc", "../browser/android/explore_sites/import_catalog_task_unittest.cc", "../browser/android/explore_sites/ntp_json_fetcher_unittest.cc", "../browser/android/history_report/data_observer_unittest.cc", @@ -3718,6 +3720,7 @@ "../browser/sync_file_system/sync_file_system_test_util.h", "../browser/sync_file_system/sync_process_runner_unittest.cc", "../browser/sync_file_system/syncable_file_system_util_unittest.cc", + "../common/apps/platform_apps/media_galleries_permission_unittest.cc", "../common/extensions/api/commands/commands_manifest_unittest.cc", "../common/extensions/api/common_extension_api_unittest.cc", "../common/extensions/api/extension_action/browser_action_manifest_unittest.cc", @@ -3769,7 +3772,6 @@ "../common/extensions/manifest_unittest.cc", "../common/extensions/permissions/chrome_permission_message_provider_unittest.cc", "../common/extensions/permissions/chrome_permission_message_rules_unittest.cc", - "../common/extensions/permissions/media_galleries_permission_unittest.cc", "../common/extensions/permissions/permission_set_unittest.cc", "../common/extensions/permissions/permissions_data_unittest.cc", "../common/extensions/permissions/settings_override_permission_unittest.cc", @@ -4148,6 +4150,7 @@ "../browser/ui/cocoa/test/run_loop_testing_unittest.mm", "../browser/ui/cocoa/touchbar/browser_window_default_touch_bar_unittest.mm", "../browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm", + "../browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm", "../browser/ui/cocoa/url_drop_target_unittest.mm", "../browser/ui/cocoa/view_resizer_pong.h", "../browser/ui/cocoa/view_resizer_pong.mm", @@ -4670,6 +4673,7 @@ "../browser/ui/search/local_ntp_uitest.cc", "../browser/ui/send_mouse_move_uitest_win.cc", "../browser/ui/signin_view_controller_interactive_uitest.cc", + "../browser/ui/startup/invalid_user_data_dir_interactive_uitest.cc", "../browser/ui/startup/startup_browser_creator_interactive_uitest.cc", "../browser/ui/tabs/window_activity_watcher_interactive_uitest.cc", "../browser/ui/translate/translate_bubble_test_utils.h",
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc index 582f7ceb..e4c73afe 100644 --- a/chrome/test/base/in_process_browser_test.cc +++ b/chrome/test/base/in_process_browser_test.cc
@@ -213,12 +213,10 @@ command_line->AppendSwitchASCII(switches::kHostWindowBounds, "0+0-1280x800"); } -#elif defined(USE_X11) - DCHECK(!display::Screen::GetScreen()); - display::Screen::SetScreenInstance( - views::test::TestDesktopScreenX11::GetInstance()); #endif + SetScreenInstance(); + // Always use a mocked password storage if OS encryption is used (which is // when anything sensitive gets stored, including Cookies). Without this on // Mac, many tests will hang waiting for a user to approve KeyChain access. @@ -373,6 +371,14 @@ return true; } +void InProcessBrowserTest::SetScreenInstance() { +#if defined(USE_X11) && !defined(OS_CHROMEOS) + DCHECK(!display::Screen::GetScreen()); + display::Screen::SetScreenInstance( + views::test::TestDesktopScreenX11::GetInstance()); +#endif +} + #if !defined(OS_MACOSX) void InProcessBrowserTest::OpenDevToolsWindow( content::WebContents* web_contents) {
diff --git a/chrome/test/base/in_process_browser_test.h b/chrome/test/base/in_process_browser_test.h index 2fd1820c..e7464399 100644 --- a/chrome/test/base/in_process_browser_test.h +++ b/chrome/test/base/in_process_browser_test.h
@@ -181,6 +181,9 @@ // successful. virtual bool SetUpUserDataDirectory() WARN_UNUSED_RESULT; + // Initializes the display::Screen instance on X11. + virtual void SetScreenInstance(); + // BrowserTestBase: void PreRunTestOnMainThread() override; void PostRunTestOnMainThread() override;
diff --git a/chrome/test/data/android/feed/feed_large.gcl.bin b/chrome/test/data/android/feed/feed_large.gcl.bin index b7653a2e..8e8462e 100644 --- a/chrome/test/data/android/feed/feed_large.gcl.bin +++ b/chrome/test/data/android/feed/feed_large.gcl.bin Binary files differ
diff --git a/chrome/test/data/android/feed/feed_paging.gcl.bin b/chrome/test/data/android/feed/feed_paging.gcl.bin index b2a0ff6..79212ba 100644 --- a/chrome/test/data/android/feed/feed_paging.gcl.bin +++ b/chrome/test/data/android/feed/feed_paging.gcl.bin Binary files differ
diff --git a/chrome/test/data/android/feed/feed_with_hero.gcl.bin b/chrome/test/data/android/feed/feed_with_hero.gcl.bin index b78d6ed..60ce43b 100644 --- a/chrome/test/data/android/feed/feed_with_hero.gcl.bin +++ b/chrome/test/data/android/feed/feed_with_hero.gcl.bin Binary files differ
diff --git a/chrome/test/data/android/feed/feed_with_overlay.gcl.bin b/chrome/test/data/android/feed/feed_with_overlay.gcl.bin index b93b406..62c7504 100644 --- a/chrome/test/data/android/feed/feed_with_overlay.gcl.bin +++ b/chrome/test/data/android/feed/feed_with_overlay.gcl.bin Binary files differ
diff --git a/chrome/test/data/arc_default_apps/test_app1/icon_100p_32.png b/chrome/test/data/arc_default_apps/test_app1/icon_100p_32.png new file mode 100644 index 0000000..1ce8901 --- /dev/null +++ b/chrome/test/data/arc_default_apps/test_app1/icon_100p_32.png Binary files differ
diff --git a/chrome/test/data/arc_default_apps/test_app1/icon_200p_32.png b/chrome/test/data/arc_default_apps/test_app1/icon_200p_32.png new file mode 100644 index 0000000..b40f6a2 --- /dev/null +++ b/chrome/test/data/arc_default_apps/test_app1/icon_200p_32.png Binary files differ
diff --git a/chrome/test/data/extensions/api_test/enterprise_device_attributes/update_manifest.xml b/chrome/test/data/extensions/api_test/enterprise_device_attributes/update_manifest.xml index cbf82cd..3e87870 100644 --- a/chrome/test/data/extensions/api_test/enterprise_device_attributes/update_manifest.xml +++ b/chrome/test/data/extensions/api_test/enterprise_device_attributes/update_manifest.xml
@@ -1,7 +1,8 @@ <?xml version='1.0' encoding='UTF-8'?> <!-- - This update manifest points to the enterprise_device_attributes.crx file. It - is meant to be used with a URLRequestMockHTTPJob. + This update manifest points to the enterprise_device_attributes.crx file. + "mock.http" is a placeholder that gets substituted with the test server + address in runtime. --> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <app appid='nbiliclbejdndfpchgkbmfoppjplbdok'>
diff --git a/chrome/test/data/extensions/api_test/enterprise_platform_keys/update_manifest.xml b/chrome/test/data/extensions/api_test/enterprise_platform_keys/update_manifest.xml index 9487a30..ae6a807 100644 --- a/chrome/test/data/extensions/api_test/enterprise_platform_keys/update_manifest.xml +++ b/chrome/test/data/extensions/api_test/enterprise_platform_keys/update_manifest.xml
@@ -1,7 +1,8 @@ <?xml version='1.0' encoding='UTF-8'?> <!-- - This update manifest points to the enterprise_platform_keys.crx file. It is - meant to be used with a URLRequestMockHTTPJob. + This update manifest points to the enterprise_platform_keys.crx file. + "mock.http" is a placeholder that gets substituted with the test server + address in runtime. --> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <app appid='aecpbnckhoppanpmefllkdkohionpmig'>
diff --git a/chrome/test/data/extensions/signin_screen_manual_test_app/update_manifest.xml b/chrome/test/data/extensions/signin_screen_manual_test_app/update_manifest.xml index 78037784..2bc4030 100644 --- a/chrome/test/data/extensions/signin_screen_manual_test_app/update_manifest.xml +++ b/chrome/test/data/extensions/signin_screen_manual_test_app/update_manifest.xml
@@ -1,8 +1,8 @@ <?xml version='1.0' encoding='UTF-8'?> <!-- - This update manifest points to the ./app_signed_by_webstore.crx file. It is - meant to be used with a URLRequestMockHTTPJob, and the hostname must be kept - in sync. + This update manifest points to the ./app_signed_by_webstore.crx file. + "mock.http" is a placeholder that gets substituted with the test server + address in runtime. --> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <app appid='bjaiihebfngildkcjkjckolinodhliff'>
diff --git a/chrome/test/data/extensions/trivial_extension/update_manifest.xml b/chrome/test/data/extensions/trivial_extension/update_manifest.xml index 86bc6f6..bf1dd7b 100644 --- a/chrome/test/data/extensions/trivial_extension/update_manifest.xml +++ b/chrome/test/data/extensions/trivial_extension/update_manifest.xml
@@ -1,7 +1,7 @@ <?xml version='1.0' encoding='UTF-8'?> <!-- - This update manifest points to the ./extension.crx file. It is meant to be - used with a URLRequestMockHTTPJob, and the hostname must be kept in sync. + This update manifest points to the ./extension.crx file. "mock.http" is a + placeholder that gets substituted with the test server address in runtime. --> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <app appid='mockepjebcnmhmhcahfddgfcdgkdifnc'>
diff --git a/chrome/test/data/extensions/trivial_platform_app/update_manifest.xml b/chrome/test/data/extensions/trivial_platform_app/update_manifest.xml index 14071838..2cceb13b 100644 --- a/chrome/test/data/extensions/trivial_platform_app/update_manifest.xml +++ b/chrome/test/data/extensions/trivial_platform_app/update_manifest.xml
@@ -1,7 +1,7 @@ <?xml version='1.0' encoding='UTF-8'?> <!-- - This update manifest points to the ./app.crx file. It is meant to be used with - a URLRequestMockHTTPJob, and the hostname must be kept in sync. + This update manifest points to the ./app.crx file. "mock.http" is a + placeholder that gets substituted with the test server address in runtime. --> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <app appid='mockapnacjbcdncmpkjngjalkhphojek'>
diff --git a/chrome/test/data/webui/cr_elements/cr_slider_test.js b/chrome/test/data/webui/cr_elements/cr_slider_test.js index 2978110..a811afb 100644 --- a/chrome/test/data/webui/cr_elements/cr_slider_test.js +++ b/chrome/test/data/webui/cr_elements/cr_slider_test.js
@@ -61,8 +61,9 @@ pointerEvent('pointermove', ratio); } - function pointerUp(ratio) { - pointerEvent('pointerup', ratio); + function pointerUp() { + // Ignores clientX for pointerup event. + pointerEvent('pointerup', 0); } // Ensure that value-changed event bubbles, since users of cr-slider rely on @@ -118,13 +119,35 @@ assertEquals(0, crSlider.value); pointerMove(2); assertEquals(100, crSlider.value); - pointerUp(0); + pointerUp(); assertEquals(100, crSlider.value); assertEquals(0, crSlider.draggingEventTracker_.listeners_.length); pointerMove(.25); assertEquals(100, crSlider.value); }); + test('update value instantly both off and on', () => { + crSlider.updateValueInstantly = false; + assertEquals(0, crSlider.value); + pointerDown(.5); + assertEquals(0, crSlider.value); + pointerUp(); + assertEquals(50, crSlider.value); + + // Once |updateValueInstantly| is turned on, |value| should start updating + // again during drag. + pointerDown(0); + assertEquals(50, crSlider.value); + crSlider.updateValueInstantly = true; + pointerMove(0); + assertEquals(0, crSlider.value); + crSlider.updateValueInstantly = false; + pointerMove(.4); + assertEquals(0, crSlider.value); + pointerUp(); + assertEquals(40, crSlider.value); + }); + test('snaps to closest value', () => { crSlider.snaps = true; pointerDown(.501); @@ -164,11 +187,13 @@ assertEquals('8', crSlider.getAttribute('aria-valuemax')); assertEquals('4', crSlider.getAttribute('aria-valuetext')); assertEquals('4', crSlider.getAttribute('aria-valuenow')); + assertEquals('', crSlider.$.label.innerHTML.trim()); assertEquals(2, crSlider.value); crSlider.value = 100; assertEquals(3, crSlider.value); assertEquals('8', crSlider.getAttribute('aria-valuetext')); assertEquals('8', crSlider.getAttribute('aria-valuenow')); + assertEquals('', crSlider.$.label.innerHTML.trim()); crSlider.ticks = [ { value: 10, @@ -188,9 +213,11 @@ assertEquals('1', crSlider.getAttribute('aria-valuemin')); assertEquals('3', crSlider.getAttribute('aria-valuemax')); assertEquals('Third', crSlider.getAttribute('aria-valuetext')); + assertEquals('Third', crSlider.$.label.innerHTML.trim()); assertEquals('3', crSlider.getAttribute('aria-valuenow')); crSlider.value = 1; assertEquals('Second', crSlider.getAttribute('aria-valuetext')); assertEquals('20', crSlider.getAttribute('aria-valuenow')); + assertEquals('Second', crSlider.$.label.innerHTML.trim()); }); });
diff --git a/chrome/test/data/webui/extensions/runtime_host_permissions_test.js b/chrome/test/data/webui/extensions/runtime_host_permissions_test.js index 308fe44ee..a86b2a6a 100644 --- a/chrome/test/data/webui/extensions/runtime_host_permissions_test.js +++ b/chrome/test/data/webui/extensions/runtime_host_permissions_test.js
@@ -27,7 +27,6 @@ const permissions = { simplePermissions: ['permission 1', 'permission 2'], hostAccess: HostAccess.ON_CLICK, - runtimeHostPermissions: [], }; element.set('permissions', permissions); @@ -52,9 +51,13 @@ // Setting the mode to on specific sites should display the runtime hosts // list. element.set('permissions.hostAccess', HostAccess.ON_SPECIFIC_SITES); - element.set( - 'permissions.runtimeHostPermissions', - ['https://example.com', 'https://chromium.org']); + element.set('permissions.specificSiteControls', { + hasAllHosts: false, + hosts: [ + {host: 'https://example.com', granted: true}, + {host: 'https://chromium.org', granted: true} + ], + }); Polymer.dom.flush(); expectEquals(HostAccess.ON_SPECIFIC_SITES, selectHostAccess.value); expectTrue(testIsVisible('#hosts')); @@ -66,7 +69,6 @@ const permissions = { simplePermissions: ['permission 1', 'permission 2'], hostAccess: HostAccess.ON_CLICK, - runtimeHostPermissions: [], }; element.set('permissions', permissions); @@ -98,9 +100,7 @@ test('on select sites cancel', function() { const permissions = { - simplePermissions: ['permission 1', 'permission 2'], hostAccess: HostAccess.ON_CLICK, - runtimeHostPermissions: [], }; element.permissions = permissions; @@ -133,7 +133,6 @@ const permissions = { simplePermissions: ['permission 1', 'permission 2'], hostAccess: HostAccess.ON_CLICK, - runtimeHostPermissions: [], }; element.set('permissions', permissions); @@ -172,7 +171,13 @@ const permissions = { simplePermissions: [], hostAccess: HostAccess.ON_SPECIFIC_SITES, - runtimeHostPermissions: ['http://www.example.com'], + specificSiteControls: { + hasAllHosts: false, + hosts: [ + {host: 'https://www.example.com/*', granted: true}, + {host: 'https://*.google.com', granted: false} + ], + }, }; element.set('permissions', permissions); @@ -195,7 +200,13 @@ const permissions = { simplePermissions: [], hostAccess: HostAccess.ON_SPECIFIC_SITES, - runtimeHostPermissions: ['https://example.com', 'https://chromium.org'], + specificSiteControls: { + hasAllHosts: false, + hosts: [ + {host: 'https://example.com', granted: true}, + {host: 'https://chromium.org', granted: true} + ], + }, }; element.set('permissions', permissions); Polymer.dom.flush(); @@ -213,7 +224,7 @@ remove.click(); return delegate.whenCalled('removeRuntimeHostPermission').then((args) => { expectEquals(ITEM_ID, args[0] /* id */); - expectEquals('https://example.com', args[1] /* site */); + expectEquals('https://chromium.org', args[1] /* site */); expectFalse(actionMenu.open); }); }); @@ -222,7 +233,13 @@ const permissions = { simplePermissions: [], hostAccess: HostAccess.ON_SPECIFIC_SITES, - runtimeHostPermissions: ['https://example.com', 'https://chromium.org'], + specificSiteControls: { + hasAllHosts: false, + hosts: [ + {host: 'https://example.com', granted: true}, + {host: 'https://chromium.org', granted: true} + ], + }, }; element.set('permissions', permissions); Polymer.dom.flush(); @@ -240,6 +257,6 @@ assertTrue(!!dialog); expectTrue(dialog.$.dialog.open); expectFalse(dialog.updateHostAccess); - expectEquals('https://example.com', dialog.currentSite); + expectEquals('https://chromium.org', dialog.currentSite); }); });
diff --git a/chrome/test/data/webui/md_bookmarks/dnd_manager_test.js b/chrome/test/data/webui/md_bookmarks/dnd_manager_test.js index 6a709ba..b31575ffc 100644 --- a/chrome/test/data/webui/md_bookmarks/dnd_manager_test.js +++ b/chrome/test/data/webui/md_bookmarks/dnd_manager_test.js
@@ -65,15 +65,14 @@ }; } - function startInternalDrag(dragElement) { - MockInteractions.down(dragElement); + function simulateDragStart(dragElement) { + dispatchDragEvent('dragstart', dragElement); move(dragElement, MockInteractions.topLeftOfNode(dragElement)); } function move(target, dest) { - MockInteractions.move( - target, {x: 0, y: 0}, dest || MockInteractions.middleOfNode(target), - -1); + dispatchDragEvent( + 'dragover', target, dest || MockInteractions.middleOfNode(target)); } function getDragIds() { @@ -109,6 +108,10 @@ store.replaceSingleton(); chrome.bookmarks.move = function(id, details) {}; + chrome.bookmarkManagerPrivate.startDrag = function( + idList, dragNodeIndex, isFromTouch) { + dndManager.dragInfo_.setNativeDragData(createDragData(idList)); + }; app = document.createElement('bookmarks-app'); replaceBody(app); @@ -137,7 +140,7 @@ const dragElement = getListItem('13'); let dragTarget = getListItem('12'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertDeepEquals(['13'], getDragIds()); @@ -173,7 +176,7 @@ const dragElement = getFolderNode('112'); const dragTarget = getFolderNode('111'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertEquals( DropPosition.ON | DropPosition.ABOVE, @@ -186,7 +189,7 @@ test('drag an item into a sidebar folder', function() { const dragElement = getListItem('13'); let dragTarget = getFolderNode('2'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); // Items can only be dragged onto sidebar folders, not above or below. assertEquals( @@ -206,7 +209,7 @@ const dragTarget = getFolderNode('112'); // Folders cannot be dragged into their descendants. - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertEquals( DropPosition.NONE, dndManager.calculateValidDropPositions_(dragTarget)); @@ -219,7 +222,7 @@ const dragElement = getFolderNode('15'); const dragTarget = getFolderNode('11'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); // Drags below an open folder are not allowed. assertEquals( @@ -230,13 +233,13 @@ assertDragStyle(dragTarget, DRAG_STYLE.ON); - MockInteractions.up(dragElement); + dispatchDragEvent('dragend', dragElement); assertDragStyle(dragTarget, DRAG_STYLE.NONE); store.data.folderOpenState.set('11', false); store.notifyObservers(); - startInternalDrag(dragElement); + simulateDragStart(dragElement); // Drags below a closed folder are allowed. assertEquals( @@ -248,7 +251,7 @@ // Dragging multiple items. store.data.selection.items = new Set(['13', '15']); let dragElement = getListItem('13'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertDeepEquals(['13', '15'], getDragIds()); // The dragged items should not be allowed to be dragged around any selected @@ -262,17 +265,17 @@ assertEquals( DropPosition.NONE, dndManager.calculateValidDropPositions_(getListItem('15'))); - MockInteractions.up(dragElement); + dispatchDragEvent('dragend', dragElement); // Dragging an unselected item should only drag the unselected item. dragElement = getListItem('14'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertDeepEquals(['14'], getDragIds()); - MockInteractions.up(dragElement); + dispatchDragEvent('dragend', dragElement); // Dragging a folder node should only drag the node. dragElement = getListItem('11'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertDeepEquals(['11'], getDragIds()); }); @@ -297,13 +300,13 @@ const dragTarget = getListItem('13'); // Drag a folder onto the list. - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertDeepEquals(['112'], getDragIds()); move(dragTarget, MockInteractions.topLeftOfNode(dragTarget)); assertDragStyle(dragTarget, DRAG_STYLE.ABOVE); - MockInteractions.up(dragTarget); + dispatchDragEvent('dragend', dragTarget); // Folders should not be able to dragged onto themselves in the list. dndManager.handleChromeDragEnter_(createDragData(['11'])); @@ -368,11 +371,6 @@ }); test('simple native drop end to end', function() { - let draggedIds; - chrome.bookmarkManagerPrivate.startDrag = function(nodes, isTouch) { - draggedIds = nodes; - }; - let dropParentId; let dropIndex; chrome.bookmarkManagerPrivate.drop = function(parentId, index) { @@ -383,14 +381,9 @@ const dragElement = getListItem('13'); const dragTarget = getListItem('12'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertDeepEquals(['13'], getDragIds()); - dispatchDragEvent('dragstart', dragElement); - assertEquals(null, dndManager.internalDragElement_); - assertDeepEquals(['13'], draggedIds); - dndManager.handleChromeDragEnter_(createDragData(draggedIds)); - dispatchDragEvent( 'dragover', dragTarget, MockInteractions.topLeftOfNode(dragTarget)); assertDragStyle(dragTarget, DRAG_STYLE.ABOVE); @@ -403,34 +396,6 @@ assertDragStyle(dragTarget, DRAG_STYLE.NONE); }); - - test('simple internal drop end to end', function() { - let moveId; - let moveParentId; - let moveIndex; - chrome.bookmarks.move = function(id, details) { - moveId = id; - moveParentId = details.parentId; - moveIndex = details.index; - }; - - const dragElement = getListItem('13'); - const dragTarget = getListItem('12'); - - startInternalDrag(dragElement); - assertDeepEquals(['13'], getDragIds()); - - move(dragTarget, MockInteractions.topLeftOfNode(dragTarget)); - assertDragStyle(dragTarget, DRAG_STYLE.ABOVE); - - MockInteractions.up(dragTarget); - assertEquals('13', moveId); - assertEquals('1', moveParentId); - assertEquals(1, moveIndex); - - assertDragStyle(dragTarget, DRAG_STYLE.NONE); - }); - test('auto expander', function() { const timerProxy = new bookmarks.TestTimerProxy(); timerProxy.immediatelyResolveTimeouts = false; @@ -445,7 +410,7 @@ const dragElement = getFolderNode('14'); let dragTarget = getFolderNode('15'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); // Dragging onto folders without children doesn't update the auto expander. move(dragTarget); @@ -499,20 +464,20 @@ const dragTarget = list; // Dragging onto an empty list. - startInternalDrag(dragElement); + simulateDragStart(dragElement); move(dragTarget); assertEquals( DropPosition.ON, dndManager.calculateValidDropPositions_(dragTarget)); assertDragStyle(dragTarget, DRAG_STYLE.ON); - MockInteractions.up(dragTarget); + dispatchDragEvent('dragend', dragTarget); // Dragging onto a non-empty list. store.data.selectedFolder = '11'; store.notifyObservers(); - startInternalDrag(dragElement); + simulateDragStart(dragElement); move(dragTarget); assertEquals( @@ -529,15 +494,15 @@ // Dragging an item not in the selection selects the dragged item and // deselects the previous selection. let dragElement = getListItem('14'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertDeepEquals(['14'], normalizeIterable(store.data.selection.items)); - MockInteractions.up(dragElement); + dispatchDragEvent('dragend', dragElement); // Dragging a folder node deselects any selected items in the bookmark list. dragElement = getFolderNode('15'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertDeepEquals([], normalizeIterable(store.data.selection.items)); - MockInteractions.up(dragElement); + dispatchDragEvent('dragend', dragElement); }); test('cannot drag items when editing is disabled', function() { @@ -545,7 +510,7 @@ store.notifyObservers(); const dragElement = getFolderNode('11'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertFalse(dndManager.dragInfo_.isDragValid()); }); @@ -554,11 +519,11 @@ store.notifyObservers(); let dragElement = getFolderNode('1'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertFalse(dndManager.dragInfo_.isDragValid()); dragElement = getFolderNode('2'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); assertFalse(dndManager.dragInfo_.isDragValid()); }); @@ -567,7 +532,7 @@ store.notifyObservers(); const dragElement = getListItem('12'); - startInternalDrag(dragElement); + simulateDragStart(dragElement); // Can't drag onto the unmodifiable node. const dragTarget = getFolderNode('2'); @@ -575,32 +540,4 @@ assertEquals( DropPosition.NONE, dndManager.calculateValidDropPositions_(dragTarget)); }); - - test('ensure drag and drop chip shows', function() { - const dragElement = getListItem('13'); - const dragTarget = getFolderNode('2'); - - startInternalDrag(dragElement); - - move(dragTarget, {x: 50, y: 80}); - assertTrue(!!dndManager.chip_); - const dndChip = dndManager.dndChip; - assertEquals('50px', dndChip.style.getPropertyValue('--mouse-x')); - assertEquals('80px', dndChip.style.getPropertyValue('--mouse-y')); - assertTrue(dndChip.showing_); - - MockInteractions.up(dragElement); - assertFalse(dndChip.showing_); - }); - - test('drag starts after minimal move distance', function() { - const dragElement = getListItem('13'); - - MockInteractions.down(dragElement); - move(dragElement); - assertFalse(dndManager.dragInfo_.isDragValid()); - - move(dragElement, MockInteractions.topLeftOfNode(dragElement)); - assertTrue(dndManager.dragInfo_.isDragValid()); - }); });
diff --git a/chrome/test/data/webui/md_history/history_list_test.js b/chrome/test/data/webui/md_history/history_list_test.js index 698c8abb..fc5c12df 100644 --- a/chrome/test/data/webui/md_history/history_list_test.js +++ b/chrome/test/data/webui/md_history/history_list_test.js
@@ -218,6 +218,7 @@ app.historyResult(createHistoryInfo(), ADDITIONAL_RESULTS); return PolymerTest.flushTasks().then(function() { + Polymer.dom.flush(); const items = polymerSelectAll(element, 'history-item'); assertTrue(items[3].isCardStart); assertTrue(items[5].isCardEnd); @@ -241,6 +242,7 @@ return PolymerTest.flushTasks(); }) .then(function() { + Polymer.dom.flush(); const items = polymerSelectAll(element, 'history-item'); assertEquals(element.historyData_.length, 5);
diff --git a/chrome/test/data/webui/settings/device_page_tests.js b/chrome/test/data/webui/settings/device_page_tests.js index 41c61eb..b7cd8d8 100644 --- a/chrome/test/data/webui/settings/device_page_tests.js +++ b/chrome/test/data/webui/settings/device_page_tests.js
@@ -717,7 +717,7 @@ width: 1920, height: 1080, }, - availableDisplayZoomFactors: [1], + availableDisplayZoomFactors: [1, 1.25, 1.5, 2], }; fakeSystemDisplay.addDisplayForTest(display); }; @@ -831,6 +831,25 @@ expectTrue(displayPage.displays[0].isPrimary); expectTrue(displayPage.showMirror_(false, displayPage.displays)); expectTrue(displayPage.isMirrored_(displayPage.displays)); + + // Ensure that the zoom value remains unchanged while draggging. + function pointerEvent(eventType, ratio) { + const crSlider = displayPage.$.displaySizeSlider.$.slider; + const rect = crSlider.$.barContainer.getBoundingClientRect(); + crSlider.dispatchEvent(new PointerEvent(eventType, { + buttons: 1, + pointerId: 1, + clientX: rect.left + (ratio * rect.width), + })); + } + + expectEquals(1, displayPage.selectedZoomPref_.value); + pointerEvent('pointerdown', .6); + expectEquals(1, displayPage.selectedZoomPref_.value); + pointerEvent('pointermove', .3); + expectEquals(1, displayPage.selectedZoomPref_.value); + pointerEvent('pointerup', 0); + expectEquals(1.25, displayPage.selectedZoomPref_.value); }); });
diff --git a/chrome/test/data/webui/settings/multidevice_page_tests.js b/chrome/test/data/webui/settings/multidevice_page_tests.js index 1e03e972..3d63530 100644 --- a/chrome/test/data/webui/settings/multidevice_page_tests.js +++ b/chrome/test/data/webui/settings/multidevice_page_tests.js
@@ -138,15 +138,19 @@ }); setup(function() { + settings.navigateTo(settings.routes.MULTIDEVICE); browserProxy = new TestMultideviceBrowserProxy(); settings.MultiDeviceBrowserProxyImpl.instance_ = browserProxy; + const whenInitialized = browserProxy.whenCalled('getPageContentData'); PolymerTest.clearBody(); multidevicePage = document.createElement('settings-multidevice-page'); assertTrue(!!multidevicePage); document.body.appendChild(multidevicePage); - Polymer.dom.flush(); + return whenInitialized.then(() => { + Polymer.dom.flush(); + }); }); teardown(function() {
diff --git a/chrome/test/data/webui/settings/multidevice_subpage_tests.js b/chrome/test/data/webui/settings/multidevice_subpage_tests.js index 23cee3f..7a254b41 100644 --- a/chrome/test/data/webui/settings/multidevice_subpage_tests.js +++ b/chrome/test/data/webui/settings/multidevice_subpage_tests.js
@@ -148,9 +148,9 @@ assertFalse(!!multideviceSubpage.$$('#messagesItem')); }); - test('clicking EasyUnlock item routes to screen lock page', function() { + test('clicking SmartLock item routes to SmartLock subpage', function() { multideviceSubpage.$$('#smartLockItem').$.card.click(); - assertEquals(settings.getCurrentRoute(), settings.routes.LOCK_SCREEN); + assertEquals(settings.getCurrentRoute(), settings.routes.SMART_LOCK); }); test('AndroidMessages item shows button when not set up', function() {
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc index 04d375f..ae3d1ff7 100644 --- a/chrome/test/ppapi/ppapi_browsertest.cc +++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -6,6 +6,7 @@ #include "base/callback.h" #include "base/macros.h" +#include "base/optional.h" #include "base/path_service.h" #include "base/test/test_timeouts.h" #include "base/threading/thread_restrictions.h" @@ -39,13 +40,19 @@ #include "extensions/test/extension_test_message_listener.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/public/cpp/system/data_pipe.h" #include "net/base/net_errors.h" +#include "net/ssl/ssl_info.h" #include "ppapi/shared_impl/test_utils.h" #include "rlz/buildflags/buildflags.h" #include "services/network/public/cpp/features.h" +#include "services/network/public/mojom/host_resolver.mojom.h" #include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/network_service_test.mojom.h" +#include "services/network/public/mojom/tcp_socket.mojom.h" +#include "services/network/public/mojom/tls_socket.mojom.h" #include "services/network/public/mojom/udp_socket.mojom.h" +#include "services/network/test/test_network_context.h" #include "services/service_manager/public/cpp/connector.h" #if defined(OS_MACOSX) @@ -326,12 +333,24 @@ PPAPI_SOCKET_TEST(TCPSocket_Interface_1_0); PPAPI_SOCKET_TEST(TCPSocket_UnexpectedCalls); -TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(TCPServerSocketPrivate) -TEST_PPAPI_NACL(TCPServerSocketPrivate) +TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(TCPServerSocketPrivate_Listen) +TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(TCPServerSocketPrivate_Backlog) +TEST_PPAPI_NACL(TCPServerSocketPrivate_Listen) +TEST_PPAPI_NACL(TCPServerSocketPrivate_Backlog) -TEST_PPAPI_OUT_OF_PROCESS_WITH_SSL_SERVER(TCPSocketPrivate) +TEST_PPAPI_OUT_OF_PROCESS_WITH_SSL_SERVER(TCPSocketPrivate_Basic) +TEST_PPAPI_OUT_OF_PROCESS_WITH_SSL_SERVER(TCPSocketPrivate_ReadWrite) +TEST_PPAPI_OUT_OF_PROCESS_WITH_SSL_SERVER(TCPSocketPrivate_ReadWriteSSL) +TEST_PPAPI_OUT_OF_PROCESS_WITH_SSL_SERVER(TCPSocketPrivate_ConnectAddress) +TEST_PPAPI_OUT_OF_PROCESS_WITH_SSL_SERVER(TCPSocketPrivate_SetOption) +TEST_PPAPI_OUT_OF_PROCESS_WITH_SSL_SERVER(TCPSocketPrivate_LargeRead) -TEST_PPAPI_NACL_WITH_SSL_SERVER(TCPSocketPrivate) +TEST_PPAPI_NACL_WITH_SSL_SERVER(TCPSocketPrivate_Basic) +TEST_PPAPI_NACL_WITH_SSL_SERVER(TCPSocketPrivate_ReadWrite) +TEST_PPAPI_NACL_WITH_SSL_SERVER(TCPSocketPrivate_ReadWriteSSL) +TEST_PPAPI_NACL_WITH_SSL_SERVER(TCPSocketPrivate_ConnectAddress) +TEST_PPAPI_NACL_WITH_SSL_SERVER(TCPSocketPrivate_SetOption) +TEST_PPAPI_NACL_WITH_SSL_SERVER(TCPSocketPrivate_LargeRead) TEST_PPAPI_OUT_OF_PROCESS_WITH_SSL_SERVER(TCPSocketPrivateTrusted) @@ -350,6 +369,569 @@ RunTestViaHTTP(STRIP_PREFIXES(TCPSocketPrivateCrash_Resolve)); } +namespace { + +// Different types of TCPSocket failures to simulate. *Error means to keep the +// pipe alive while invoking the callback with an error code, and *PipeError +// means to close the pipe that the method was invoked on (not the pipe passed +// to the callback, if there was one) without invoking the callback. +// +// Note that closing a pipe after a successful operation isn't too interesting, +// as it looks just like closing the pipe on the next operation, since the +// message filter classes don't generally watch for pipe closure. +enum class TCPFailureType { + // Makes creation calls for all socket types (server, connected, and bound) + // close all Mojo pipes without doing anything. + kClosePipeOnCreate, + + kBindClosePipe, + kBindError, + + // These apply to both CreateTCPServerSocket and TCPBoundSocket::Listen(). + kCreateTCPServerSocketClosePipe, + kCreateTCPServerSocketError, + + kAcceptDropPipe, + kAcceptError, + + kConnectClosePipe, + kConnectError, + kWriteClosePipe, + kWriteError, + kReadClosePipe, + kReadError, + + // These apply to all TCPConnectedSocket configuration methods. + kSetOptionsClosePipe, + kSetOptionsError, + + kUpgradeToTLSClosePipe, + kUpgradeToTLSError, + kSSLWriteClosePipe, + kSSLWriteError, + kSSLReadClosePipe, + kSSLReadError, +}; + +net::IPEndPoint LocalAddress() { + return net::IPEndPoint(net::IPAddress::IPv4Localhost(), 1234); +} + +net::IPEndPoint RemoteAddress() { + return net::IPEndPoint(net::IPAddress::IPv4Localhost(), 12345); +} + +// Use the same class for TCPConnectedSocket and, if it's upgraded, +// TLSClientSocket, since the TLSClientSocket interface doesn't do anything. +class MockTCPConnectedSocket : public network::mojom::TCPConnectedSocket, + public network::mojom::TLSClientSocket { + public: + MockTCPConnectedSocket( + TCPFailureType tcp_failure_type, + network::mojom::TCPConnectedSocketRequest request, + network::mojom::SocketObserverPtr observer, + network::mojom::NetworkContext::CreateTCPConnectedSocketCallback callback) + : tcp_failure_type_(tcp_failure_type), + observer_(std::move(observer)), + binding_(this, std::move(request)), + tls_client_socket_binding_(this) { + if (tcp_failure_type_ == TCPFailureType::kConnectError) { + std::move(callback).Run( + net::ERR_FAILED, base::nullopt /* local_addr */, + base::nullopt /* peer_addr */, + mojo::ScopedDataPipeConsumerHandle() /* receive_stream */, + mojo::ScopedDataPipeProducerHandle() /* send_stream */); + return; + } + + mojo::DataPipe send_pipe; + mojo::DataPipe receive_pipe; + + receive_pipe_handle_ = std::move(receive_pipe.producer_handle); + send_pipe_handle_ = std::move(send_pipe.consumer_handle); + + std::move(callback).Run(net::OK, LocalAddress(), RemoteAddress(), + std::move(receive_pipe.consumer_handle), + std::move(send_pipe.producer_handle)); + ClosePipeIfNeeded(); + } + + MockTCPConnectedSocket( + TCPFailureType tcp_failure_type, + network::mojom::SocketObserverPtr observer, + network::mojom::TCPServerSocket::AcceptCallback callback) + : tcp_failure_type_(tcp_failure_type), + observer_(std::move(observer)), + binding_(this), + tls_client_socket_binding_(this) { + if (tcp_failure_type_ == TCPFailureType::kAcceptError) { + std::move(callback).Run( + net::ERR_FAILED, base::nullopt /* remote_addr */, + nullptr /* connected_socket */, + mojo::ScopedDataPipeConsumerHandle() /* receive_stream */, + mojo::ScopedDataPipeProducerHandle() /* send_stream */); + return; + } + + mojo::DataPipe send_pipe; + mojo::DataPipe receive_pipe; + + receive_pipe_handle_ = std::move(receive_pipe.producer_handle); + send_pipe_handle_ = std::move(send_pipe.consumer_handle); + + network::mojom::TCPConnectedSocketPtr connected_socket; + binding_.Bind(mojo::MakeRequest(&connected_socket)); + std::move(callback).Run(net::OK, RemoteAddress(), + std::move(connected_socket), + std::move(receive_pipe.consumer_handle), + std::move(send_pipe.producer_handle)); + ClosePipeIfNeeded(); + } + + ~MockTCPConnectedSocket() override {} + + // mojom::TCPConnectedSocket implementation: + + void UpgradeToTLS( + const net::HostPortPair& host_port_pair, + network::mojom::TLSClientSocketOptionsPtr socket_options, + const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, + network::mojom::TLSClientSocketRequest request, + network::mojom::SocketObserverPtr observer, + network::mojom::TCPConnectedSocket::UpgradeToTLSCallback callback) + override { + // Succeed or fail, keep these pipes open (Their state shouldn't matter when + // checking for failures). + observer_ = std::move(observer); + tls_client_socket_binding_.Bind(std::move(request)); + + if (tcp_failure_type_ == TCPFailureType::kUpgradeToTLSClosePipe) { + binding_.Close(); + return; + } + if (tcp_failure_type_ == TCPFailureType::kUpgradeToTLSError) { + std::move(callback).Run( + net::ERR_FAILED, mojo::ScopedDataPipeConsumerHandle(), + mojo::ScopedDataPipeProducerHandle(), base::nullopt /* ssl_info */); + return; + } + + // Invoke callback immediately, without waiting for pipes to close - tests + // that use a real NetworkContext already make sure that the class correctly + // closes the sockets when upgrading. + + mojo::DataPipe send_pipe; + mojo::DataPipe receive_pipe; + receive_pipe_handle_ = std::move(receive_pipe.producer_handle); + send_pipe_handle_ = std::move(send_pipe.consumer_handle); + + std::move(callback).Run(net::OK, std::move(receive_pipe.consumer_handle), + std::move(send_pipe.producer_handle), + net::SSLInfo()); + + if (tcp_failure_type_ == TCPFailureType::kSSLWriteClosePipe) { + observer_.reset(); + send_pipe_handle_.reset(); + } else if (tcp_failure_type_ == TCPFailureType::kSSLWriteError) { + observer_->OnWriteError(net::ERR_FAILED); + send_pipe_handle_.reset(); + } else if (tcp_failure_type_ == TCPFailureType::kSSLReadClosePipe) { + observer_.reset(); + receive_pipe_handle_.reset(); + } else if (tcp_failure_type_ == TCPFailureType::kSSLReadError) { + observer_->OnReadError(net::ERR_FAILED); + receive_pipe_handle_.reset(); + } + } + + void SetSendBufferSize(int send_buffer_size, + SetSendBufferSizeCallback callback) override { + if (tcp_failure_type_ == TCPFailureType::kSetOptionsClosePipe) { + binding_.Close(); + return; + } + DCHECK_EQ(tcp_failure_type_, TCPFailureType::kSetOptionsError); + std::move(callback).Run(net::ERR_FAILED); + } + + void SetReceiveBufferSize(int send_buffer_size, + SetSendBufferSizeCallback callback) override { + if (tcp_failure_type_ == TCPFailureType::kSetOptionsClosePipe) { + binding_.Close(); + return; + } + DCHECK_EQ(tcp_failure_type_, TCPFailureType::kSetOptionsError); + std::move(callback).Run(net::ERR_FAILED); + } + + void SetNoDelay(bool no_delay, SetNoDelayCallback callback) override { + if (tcp_failure_type_ == TCPFailureType::kSetOptionsClosePipe) { + binding_.Close(); + return; + } + DCHECK_EQ(tcp_failure_type_, TCPFailureType::kSetOptionsError); + std::move(callback).Run(false); + } + + void SetKeepAlive(bool enable, + int32_t delay_secs, + SetKeepAliveCallback callback) override { + NOTREACHED(); + } + + private: + void ClosePipeIfNeeded() { + if (tcp_failure_type_ == TCPFailureType::kWriteClosePipe) { + observer_.reset(); + send_pipe_handle_.reset(); + } else if (tcp_failure_type_ == TCPFailureType::kWriteError) { + observer_->OnWriteError(net::ERR_FAILED); + send_pipe_handle_.reset(); + } else if (tcp_failure_type_ == TCPFailureType::kReadClosePipe) { + observer_.reset(); + receive_pipe_handle_.reset(); + } else if (tcp_failure_type_ == TCPFailureType::kReadError) { + observer_->OnReadError(net::ERR_FAILED); + receive_pipe_handle_.reset(); + } + } + + const TCPFailureType tcp_failure_type_; + + network::mojom::SocketObserverPtr observer_; + + mojo::ScopedDataPipeProducerHandle receive_pipe_handle_; + mojo::ScopedDataPipeConsumerHandle send_pipe_handle_; + + mojo::Binding<network::mojom::TCPConnectedSocket> binding_; + mojo::Binding<network::mojom::TLSClientSocket> tls_client_socket_binding_; + + DISALLOW_COPY_AND_ASSIGN(MockTCPConnectedSocket); +}; + +class MockTCPServerSocket : public network::mojom::TCPServerSocket { + public: + // CreateTCPServerSocket constructor. + MockTCPServerSocket( + TCPFailureType tcp_failure_type, + network::mojom::TCPServerSocketRequest request, + network::mojom::NetworkContext::CreateTCPServerSocketCallback callback) + : tcp_failure_type_(tcp_failure_type), binding_(this) { + binding_.Bind(std::move(request)); + if (tcp_failure_type_ == TCPFailureType::kCreateTCPServerSocketError) { + std::move(callback).Run(net::ERR_FAILED, base::nullopt /* local_addr */); + return; + } + std::move(callback).Run(net::OK, LocalAddress()); + } + + // TCPBoundSocket::Listen constructor. + MockTCPServerSocket(TCPFailureType tcp_failure_type, + network::mojom::TCPServerSocketRequest request, + network::mojom::TCPBoundSocket::ListenCallback callback) + : tcp_failure_type_(tcp_failure_type), binding_(this) { + binding_.Bind(std::move(request)); + if (tcp_failure_type_ == TCPFailureType::kCreateTCPServerSocketError) { + std::move(callback).Run(net::ERR_FAILED); + return; + } + std::move(callback).Run(net::OK); + } + + ~MockTCPServerSocket() override {} + + // TCPServerSocket implementation: + void Accept(network::mojom::SocketObserverPtr observer, + AcceptCallback callback) override { + // This falls through just to keep the observer alive. + if (tcp_failure_type_ == TCPFailureType::kAcceptDropPipe) + binding_.Close(); + connected_socket_ = std::make_unique<MockTCPConnectedSocket>( + tcp_failure_type_, std::move(observer), std::move(callback)); + } + + private: + const TCPFailureType tcp_failure_type_; + + std::unique_ptr<MockTCPConnectedSocket> connected_socket_; + + mojo::Binding<network::mojom::TCPServerSocket> binding_; + + DISALLOW_COPY_AND_ASSIGN(MockTCPServerSocket); +}; + +class MockTCPBoundSocket : public network::mojom::TCPBoundSocket { + public: + MockTCPBoundSocket( + TCPFailureType tcp_failure_type, + network::mojom::TCPBoundSocketRequest request, + network::mojom::NetworkContext::CreateTCPBoundSocketCallback callback) + : tcp_failure_type_(tcp_failure_type), binding_(this) { + binding_.Bind(std::move(request)); + if (tcp_failure_type_ == TCPFailureType::kBindError) { + std::move(callback).Run(net::ERR_FAILED, base::nullopt /* local_addr */); + return; + } + std::move(callback).Run(net::OK, LocalAddress()); + } + + ~MockTCPBoundSocket() override {} + + // mojom::TCPBoundSocket implementation: + void Listen(uint32_t backlog, + network::mojom::TCPServerSocketRequest request, + ListenCallback callback) override { + // If closing the pipe, create ServerSocket anyways, to keep |request| + // alive. The callback invocation will have no effect, since it uses the + // TCPBoundSocket's pipe, which was just closed. + if (tcp_failure_type_ == TCPFailureType::kCreateTCPServerSocketClosePipe) + binding_.Close(); + server_socket_ = std::make_unique<MockTCPServerSocket>( + tcp_failure_type_, std::move(request), std::move(callback)); + } + + void Connect( + const net::AddressList& remote_addr, + network::mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options, + network::mojom::TCPConnectedSocketRequest request, + network::mojom::SocketObserverPtr observer, + ConnectCallback callback) override { + if (tcp_failure_type_ == TCPFailureType::kConnectClosePipe) + binding_.Close(); + connected_socket_ = std::make_unique<MockTCPConnectedSocket>( + tcp_failure_type_, std::move(request), std::move(observer), + std::move(callback)); + } + + private: + const TCPFailureType tcp_failure_type_; + + // Needs to be destroyed after |binding_|, as it may be holding onto a + // callback bound to the Binding. + std::unique_ptr<MockTCPServerSocket> server_socket_; + std::unique_ptr<MockTCPConnectedSocket> connected_socket_; + + mojo::Binding<network::mojom::TCPBoundSocket> binding_; + + DISALLOW_COPY_AND_ASSIGN(MockTCPBoundSocket); +}; + +class MockNetworkContext : public network::TestNetworkContext { + public: + explicit MockNetworkContext(TCPFailureType tcp_failure_type, + network::mojom::NetworkContextRequest request) + : tcp_failure_type_(tcp_failure_type), + binding_(this, std::move(request)) {} + + ~MockNetworkContext() override {} + + // network::mojom::NetworkContext implementation: + + void CreateTCPServerSocket( + const net::IPEndPoint& local_addr, + uint32_t backlog, + const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, + network::mojom::TCPServerSocketRequest request, + CreateTCPServerSocketCallback callback) override { + // If closing the pipe, create ServerSocket anyways, to keep |request| + // alive. The callback invocation will have no effect, since it uses the + // TCPBoundSocket's pipe, which was just closed. + if (tcp_failure_type_ == TCPFailureType::kCreateTCPServerSocketClosePipe) + binding_.Close(); + server_socket_ = std::make_unique<MockTCPServerSocket>( + tcp_failure_type_, std::move(request), std::move(callback)); + } + + void CreateTCPConnectedSocket( + const base::Optional<net::IPEndPoint>& local_addr, + const net::AddressList& remote_addr_list, + network::mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options, + const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, + network::mojom::TCPConnectedSocketRequest socket, + network::mojom::SocketObserverPtr observer, + CreateTCPConnectedSocketCallback callback) override { + if (tcp_failure_type_ == TCPFailureType::kConnectClosePipe) + binding_.Close(); + connected_socket_ = std::make_unique<MockTCPConnectedSocket>( + tcp_failure_type_, std::move(socket), std::move(observer), + std::move(callback)); + } + + void CreateTCPBoundSocket( + const net::IPEndPoint& local_addr, + const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, + network::mojom::TCPBoundSocketRequest request, + CreateTCPBoundSocketCallback callback) override { + if (tcp_failure_type_ == TCPFailureType::kBindClosePipe) + binding_.Close(); + // These tests only create at most one object of a given type at a time. + bound_socket_ = std::make_unique<MockTCPBoundSocket>( + tcp_failure_type_, std::move(request), std::move(callback)); + } + + void ResolveHost( + const net::HostPortPair& host, + network::mojom::ResolveHostParametersPtr optional_parameters, + network::mojom::ResolveHostClientPtr response_client) override { + response_client->OnComplete(net::OK, net::AddressList(LocalAddress())); + } + + private: + TCPFailureType tcp_failure_type_; + + std::unique_ptr<MockTCPServerSocket> server_socket_; + std::unique_ptr<MockTCPBoundSocket> bound_socket_; + std::unique_ptr<MockTCPConnectedSocket> connected_socket_; + + mojo::Binding<network::mojom::NetworkContext> binding_; + + DISALLOW_COPY_AND_ASSIGN(MockNetworkContext); +}; + +// Runs a TCP test using a MockNetworkContext, through a Mojo pipe. Using a Mojo +// pipe makes sure that everything happens asynchronously through a pipe. +#define RUN_TCP_FAILURE_TEST(test_name, failure_type) \ + do { \ + network::mojom::NetworkContextPtr network_context_proxy; \ + MockNetworkContext network_context( \ + failure_type, mojo::MakeRequest(&network_context_proxy)); \ + ppapi::SetPepperTCPNetworkContextForTesting(network_context_proxy.get()); \ + RunTestViaHTTP(LIST_TEST(test_name)); \ + ppapi::SetPepperTCPNetworkContextForTesting(nullptr); \ + } while (false) + +} // namespace + +// Macro for tests that use |WrappedUDPSocket| to simulate errors. |test_name| +// and |_test| are separate values because there are often multiple ways to get +// the same error pattern (Dropped mojo pipe and failed call, generally). +#define TCP_SOCKET_FAILURE_TEST(test_name, _test, failure_type) \ + IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, test_name) { \ + RUN_TCP_FAILURE_TEST(_test, failure_type); \ + } \ + IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, MAYBE_PPAPI_NACL(test_name)) { \ + RUN_TCP_FAILURE_TEST(_test, failure_type); \ + } \ + IN_PROC_BROWSER_TEST_F(PPAPINaClGLibcTest, MAYBE_GLIBC(test_name)) { \ + RUN_TCP_FAILURE_TEST(_test, failure_type); \ + } \ + IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_PPAPI_PNACL(test_name)) { \ + RUN_TCP_FAILURE_TEST(_test, failure_type); \ + } \ + IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClNonSfiTest, \ + MAYBE_PNACL_NONSFI(test_name)) { \ + RUN_TCP_FAILURE_TEST(_test, failure_type); \ + } + +TCP_SOCKET_FAILURE_TEST(TCPSocket_ConnectClosePipe, + TCPSocket_ConnectFails, + TCPFailureType::kConnectClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_ConnectError, + TCPSocket_ConnectFails, + TCPFailureType::kConnectError); +TCP_SOCKET_FAILURE_TEST(TCPSocket_WriteClosePipe, + TCPSocket_WriteFails, + TCPFailureType::kWriteClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_WriteError, + TCPSocket_WriteFails, + TCPFailureType::kWriteError); +TCP_SOCKET_FAILURE_TEST(TCPSocket_ReadClosePipe, + TCPSocket_ReadFails, + TCPFailureType::kReadClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_ReadError, + TCPSocket_ReadFails, + TCPFailureType::kReadError); + +TCP_SOCKET_FAILURE_TEST(TCPSocket_SetSendBufferSizeClosePipe, + TCPSocket_SetSendBufferSizeFails, + TCPFailureType::kSetOptionsClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_SetSendBufferSizeError, + TCPSocket_SetSendBufferSizeFails, + TCPFailureType::kSetOptionsError); +TCP_SOCKET_FAILURE_TEST(TCPSocket_SetReceiveBufferSizeClosePipe, + TCPSocket_SetReceiveBufferSizeFails, + TCPFailureType::kSetOptionsClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_SetReceiveBufferSizeError, + TCPSocket_SetReceiveBufferSizeFails, + TCPFailureType::kSetOptionsError); +TCP_SOCKET_FAILURE_TEST(TCPSocket_SetNoDelayClosePipe, + TCPSocket_SetNoDelayFails, + TCPFailureType::kSetOptionsClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_SetNoDelayError, + TCPSocket_SetNoDelayFails, + TCPFailureType::kSetOptionsError); + +// Can't use TCPSocket_BindFailsConnectSucceeds for this one, because +// BindClosePipe has to close the NetworkContext pipe. +TCP_SOCKET_FAILURE_TEST(TCPSocket_BindClosePipe, + TCPSocket_BindFails, + TCPFailureType::kBindClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_BindError, + TCPSocket_BindFailsConnectSucceeds, + TCPFailureType::kBindError); +TCP_SOCKET_FAILURE_TEST(TCPSocket_ListenClosePipe, + TCPSocket_ListenFails, + TCPFailureType::kCreateTCPServerSocketClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_ListenError, + TCPSocket_ListenFails, + TCPFailureType::kCreateTCPServerSocketError); +TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptClosePipe, + TCPSocket_AcceptFails, + TCPFailureType::kAcceptDropPipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptError, + TCPSocket_AcceptFails, + TCPFailureType::kAcceptError); +TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketWriteClosePipe, + TCPSocket_AcceptedSocketWriteFails, + TCPFailureType::kWriteClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketWriteError, + TCPSocket_AcceptedSocketWriteFails, + TCPFailureType::kWriteError); +TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketReadClosePipe, + TCPSocket_AcceptedSocketReadFails, + TCPFailureType::kReadClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketReadError, + TCPSocket_AcceptedSocketReadFails, + TCPFailureType::kReadError); +TCP_SOCKET_FAILURE_TEST(TCPSocket_BindConnectClosePipe, + TCPSocket_BindConnectFails, + TCPFailureType::kConnectClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocket_BindConnectError, + TCPSocket_BindConnectFails, + TCPFailureType::kConnectError); + +TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLHandshakeClosePipe, + TCPSocketPrivate_SSLHandshakeFails, + TCPFailureType::kUpgradeToTLSClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLHandshakeError, + TCPSocketPrivate_SSLHandshakeFails, + TCPFailureType::kUpgradeToTLSError); +TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLWriteClosePipe, + TCPSocketPrivate_SSLWriteFails, + TCPFailureType::kSSLWriteClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLWriteError, + TCPSocketPrivate_SSLWriteFails, + TCPFailureType::kSSLWriteError); +TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLReadClosePipe, + TCPSocketPrivate_SSLReadFails, + TCPFailureType::kSSLReadClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLReadError, + TCPSocketPrivate_SSLReadFails, + TCPFailureType::kSSLReadError); + +TCP_SOCKET_FAILURE_TEST(TCPServerSocketPrivate_ListenClosePipe, + TCPServerSocketPrivate_ListenFails, + TCPFailureType::kCreateTCPServerSocketClosePipe); +TCP_SOCKET_FAILURE_TEST(TCPServerSocketPrivate_ListenError, + TCPServerSocketPrivate_ListenFails, + TCPFailureType::kCreateTCPServerSocketError); +TCP_SOCKET_FAILURE_TEST(TCPServerSocketPrivate_AcceptClosePipe, + TCPServerSocketPrivate_AcceptFails, + TCPFailureType::kAcceptDropPipe); +TCP_SOCKET_FAILURE_TEST(TCPServerSocketPrivate_AcceptError, + TCPServerSocketPrivate_AcceptFails, + TCPFailureType::kAcceptError); + // UDPSocket tests. // Split tests into multiple tests, making it easier to isolate which tests are
diff --git a/chromecast/common/extensions_api/cast_api_permissions.cc b/chromecast/common/extensions_api/cast_api_permissions.cc index a1049a3..7836419a 100644 --- a/chromecast/common/extensions_api/cast_api_permissions.cc +++ b/chromecast/common/extensions_api/cast_api_permissions.cc
@@ -12,7 +12,6 @@ #include "base/memory/ptr_util.h" #include "extensions/common/permissions/api_permission.h" #include "extensions/common/permissions/api_permission_set.h" -#include "extensions/common/permissions/media_galleries_permission.h" #include "extensions/common/permissions/permissions_info.h" #include "extensions/common/permissions/settings_override_permission.h"
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc index 05dcf0ff..714b855 100644 --- a/chromeos/services/assistant/assistant_manager_service_impl.cc +++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -735,18 +735,12 @@ std::string AssistantManagerServiceImpl::BuildUserAgent( const std::string& arc_version) const { - int32_t os_major_version = 0; - int32_t os_minor_version = 0; - int32_t os_bugfix_version = 0; - base::SysInfo::OperatingSystemVersionNumbers( - &os_major_version, &os_minor_version, &os_bugfix_version); - std::string user_agent; base::StringAppendF(&user_agent, - "Mozilla/5.0 (X11; CrOS %s %d.%d.%d; %s) " + "Mozilla/5.0 (X11; CrOS %s %s; %s) " "AppleWebKit/%d.%d (KHTML, like Gecko)", base::SysInfo::OperatingSystemArchitecture().c_str(), - os_major_version, os_minor_version, os_bugfix_version, + base::SysInfo::OperatingSystemVersion().c_str(), base::SysInfo::GetLsbReleaseBoard().c_str(), WEBKIT_VERSION_MAJOR, WEBKIT_VERSION_MINOR);
diff --git a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc index 18e88d3c..5aeb0f7 100644 --- a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc +++ b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc
@@ -13,9 +13,6 @@ #include "chromeos/components/proximity_auth/logging/logging.h" #include "chromeos/services/multidevice_setup/host_status_provider_impl.h" #include "chromeos/services/multidevice_setup/setup_flow_completion_recorder.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" -#include "components/cryptauth/remote_device_ref.h" -#include "components/cryptauth/software_feature_state.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -76,7 +73,7 @@ registry->RegisterInt64Pref(kExistingUserChromebookAddedPrefName, kTimestampNotSet); registry->RegisterStringPref( - kHostDeviceIdFromMostRecentHostStatusUpdatePrefName, kNoHost); + kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName, kNoHost); } AccountStatusChangeDelegateNotifierImpl:: @@ -103,9 +100,12 @@ kExistingUserChromebookAddedPrefName[] = "multidevice_setup.existing_user_chromebook_added"; +// Note that, despite the pref string name, this pref only records the IDs of +// verified hosts. In particular, if a host has been set but is waiting for +// verification, it will not recorded. // static const char AccountStatusChangeDelegateNotifierImpl:: - kHostDeviceIdFromMostRecentHostStatusUpdatePrefName[] = + kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName[] = "multidevice_setup.host_device_id_from_most_recent_sync"; AccountStatusChangeDelegateNotifierImpl:: @@ -118,7 +118,7 @@ pref_service_(pref_service), setup_flow_completion_recorder_(setup_flow_completion_recorder), clock_(clock) { - host_device_id_from_most_recent_update_ = + verified_host_device_id_from_most_recent_update_ = LoadHostDeviceIdFromEndOfPreviousSession(); host_status_provider_->AddObserver(this); } @@ -137,27 +137,30 @@ return; } - // Track and update host info. - base::Optional<std::string> host_device_id_before_update = - host_device_id_from_most_recent_update_; + // Track and update verified host info. + base::Optional<std::string> verified_host_device_id_before_update = + verified_host_device_id_from_most_recent_update_; - // Check if a host has been set. - if (host_status_with_device.host_device()) { - host_device_id_from_most_recent_update_ = + // Check if a host has been verified. + if (host_status_with_device.host_status() == + mojom::HostStatus::kHostVerified) { + verified_host_device_id_from_most_recent_update_ = host_status_with_device.host_device()->GetDeviceId(); pref_service_->SetString( - kHostDeviceIdFromMostRecentHostStatusUpdatePrefName, - *host_device_id_from_most_recent_update_); + kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName, + *verified_host_device_id_from_most_recent_update_); } else { // No host set. - host_device_id_from_most_recent_update_.reset(); + verified_host_device_id_from_most_recent_update_.reset(); + pref_service_->SetString( + kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName, kNoHost); } CheckForNewUserPotentialHostExistsEvent(host_status_with_device); CheckForExistingUserHostSwitchedEvent(host_status_with_device, - host_device_id_before_update); - CheckForExistingUserChromebookAddedEvent(host_status_with_device, - host_device_id_before_update); + verified_host_device_id_before_update); + CheckForExistingUserChromebookAddedEvent( + host_status_with_device, verified_host_device_id_before_update); } void AccountStatusChangeDelegateNotifierImpl:: @@ -165,7 +168,7 @@ const HostStatusProvider::HostStatusWithDevice& host_status_with_device) { // We only check for new user events if there is no enabled host. - if (host_device_id_from_most_recent_update_) + if (verified_host_device_id_from_most_recent_update_) return; // If the observer has been notified of this event before, the user is not @@ -190,14 +193,17 @@ void AccountStatusChangeDelegateNotifierImpl:: CheckForExistingUserHostSwitchedEvent( const HostStatusProvider::HostStatusWithDevice& host_status_with_device, - const base::Optional<std::string>& host_device_id_before_update) { - // The host switched event requires both a pre-update and a post-update host. - if (!host_device_id_from_most_recent_update_ || - !host_device_id_before_update) { + const base::Optional<std::string>& + verified_host_device_id_before_update) { + // The host switched event requires both a pre-update and a post-update + // verified host. + if (!verified_host_device_id_from_most_recent_update_ || + !verified_host_device_id_before_update) { return; } // If the host stayed the same, there was no switch. - if (*host_device_id_from_most_recent_update_ == *host_device_id_before_update) + if (*verified_host_device_id_from_most_recent_update_ == + *verified_host_device_id_before_update) return; delegate()->OnConnectedHostSwitchedForExistingUser( @@ -209,11 +215,13 @@ void AccountStatusChangeDelegateNotifierImpl:: CheckForExistingUserChromebookAddedEvent( const HostStatusProvider::HostStatusWithDevice& host_status_with_device, - const base::Optional<std::string>& host_device_id_before_update) { - // The Chromebook added event requires that a set host was found by the - // update, i.e. there was no host before the host status update but afterward - // there is a set host. - if (!host_device_id_from_most_recent_update_ || host_device_id_before_update) + const base::Optional<std::string>& + verified_host_device_id_before_update) { + // The Chromebook added event requires that a verified host was found by the + // update, i.e. there was no verified host before the host status update but + // afterward there was a verified host. + if (!verified_host_device_id_from_most_recent_update_ || + verified_host_device_id_before_update) return; delegate()->OnNewChromebookAddedForExistingUser( @@ -224,11 +232,12 @@ base::Optional<std::string> AccountStatusChangeDelegateNotifierImpl:: LoadHostDeviceIdFromEndOfPreviousSession() { - std::string host_device_id_from_most_recent_update = pref_service_->GetString( - kHostDeviceIdFromMostRecentHostStatusUpdatePrefName); - if (host_device_id_from_most_recent_update.empty()) + std::string verified_host_device_id_from_most_recent_update = + pref_service_->GetString( + kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName); + if (verified_host_device_id_from_most_recent_update.empty()) return base::nullopt; - return host_device_id_from_most_recent_update; + return verified_host_device_id_from_most_recent_update; } } // namespace multidevice_setup
diff --git a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h index 66950f8..de12cfb 100644 --- a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h +++ b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h
@@ -62,7 +62,8 @@ static const char kExistingUserHostSwitchedPrefName[]; static const char kExistingUserChromebookAddedPrefName[]; - static const char kHostDeviceIdFromMostRecentHostStatusUpdatePrefName[]; + static const char + kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName[]; AccountStatusChangeDelegateNotifierImpl( HostStatusProvider* host_status_provider, @@ -84,17 +85,17 @@ const HostStatusProvider::HostStatusWithDevice& host_status_with_device); void CheckForExistingUserHostSwitchedEvent( const HostStatusProvider::HostStatusWithDevice& host_status_with_device, - const base::Optional<std::string>& host_device_id_before_update); + const base::Optional<std::string>& verified_host_device_id_before_update); void CheckForExistingUserChromebookAddedEvent( const HostStatusProvider::HostStatusWithDevice& host_status_with_device, - const base::Optional<std::string>& host_device_id_before_update); + const base::Optional<std::string>& verified_host_device_id_before_update); // Loads data from previous session using PrefService. base::Optional<std::string> LoadHostDeviceIdFromEndOfPreviousSession(); // Set to base::nullopt if there was no enabled host in the most recent // host status update. - base::Optional<std::string> host_device_id_from_most_recent_update_; + base::Optional<std::string> verified_host_device_id_from_most_recent_update_; mojom::AccountStatusChangeDelegatePtr delegate_ptr_; HostStatusProvider* host_status_provider_;
diff --git a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl_unittest.cc b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl_unittest.cc index 2e7aeb6..aa3a476 100644 --- a/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl_unittest.cc +++ b/chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl_unittest.cc
@@ -15,6 +15,7 @@ #include "chromeos/services/multidevice_setup/fake_host_status_provider.h" #include "chromeos/services/multidevice_setup/fake_setup_flow_completion_recorder.h" #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h" +#include "components/cryptauth/remote_device_ref.h" #include "components/cryptauth/remote_device_test_util.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "testing/gtest/include/gtest/gtest.h" @@ -90,7 +91,7 @@ cryptauth::RemoteDevice::GenerateDeviceId(old_host_key); test_pref_service_->SetString( AccountStatusChangeDelegateNotifierImpl:: - kHostDeviceIdFromMostRecentHostStatusUpdatePrefName, + kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName, old_host_device_id); } @@ -112,6 +113,12 @@ kExistingUserChromebookAddedPrefName); } + std::string GetMostRecentVerifiedHostDeviceIdPref() { + return test_pref_service_->GetString( + AccountStatusChangeDelegateNotifierImpl:: + kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName); + } + FakeAccountStatusChangeDelegate* fake_delegate() { return fake_delegate_.get(); } @@ -216,35 +223,35 @@ NotifiesObserverForHostSwitchEvents) { BuildAccountStatusChangeDelegateNotifier(); SetAccountStatusChangeDelegatePtr(); - // Verify the delegate initializes to 0. + // Check the delegate initializes to 0. EXPECT_EQ(0u, fake_delegate()->num_existing_user_host_switched_events_handled()); - // Set initial host. + // Set initially verified host. SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); // Host was set but has never been switched. EXPECT_EQ(0u, fake_delegate()->num_existing_user_host_switched_events_handled()); - // Switch hosts. + // Switch to new verified host. SetHostWithStatus(mojom::HostStatus::kHostVerified, cryptauth::RemoteDeviceRefBuilder() - .SetPublicKey(kFakePhoneKey + "#1") - .SetName(kFakePhoneName + "#1") + .SetPublicKey(kFakePhoneKey + "A") + .SetName(kFakePhoneName + "A") .Build()); EXPECT_EQ(1u, fake_delegate()->num_existing_user_host_switched_events_handled()); - // Switch to another new host. + // Switch to a different new verified host. SetHostWithStatus(mojom::HostStatus::kHostVerified, cryptauth::RemoteDeviceRefBuilder() - .SetPublicKey(kFakePhoneKey + "#2") - .SetName(kFakePhoneName + "#2") + .SetPublicKey(kFakePhoneKey + "B") + .SetName(kFakePhoneName + "B") .Build()); EXPECT_EQ(2u, fake_delegate()->num_existing_user_host_switched_events_handled()); - // Switch back to initial host. + // Switch back to initial host (verified). SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); EXPECT_EQ(3u, fake_delegate()->num_existing_user_host_switched_events_handled()); @@ -254,7 +261,7 @@ SettingSameHostTriggersNoHostSwitchedEvent) { BuildAccountStatusChangeDelegateNotifier(); SetAccountStatusChangeDelegatePtr(); - // Set initial host. + // Set initially verified host. SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); // Set to host with identical information. SetHostWithStatus(mojom::HostStatus::kHostVerified, @@ -270,9 +277,9 @@ ChangingHostDevicesTriggersHostSwitchEventWhenHostNameIsUnchanged) { BuildAccountStatusChangeDelegateNotifier(); SetAccountStatusChangeDelegatePtr(); - // Set initial host. + // Set initially verified host. SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); - // Set to host with same name but different key. + // Set to verified host with same name but different key. SetHostWithStatus(mojom::HostStatus::kHostVerified, cryptauth::RemoteDeviceRefBuilder() .SetPublicKey(kFakePhoneKey + "alternate") @@ -283,22 +290,79 @@ } TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest, - VerifyingHostTriggersNoHostSwtichEvent) { + VerifyingSetHostTriggersNoHostSwtichEvent) { BuildAccountStatusChangeDelegateNotifier(); SetAccountStatusChangeDelegatePtr(); - // Set initial host but do not verify + // Set initial host but do not verify. SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, kFakePhone); - // Verify host + // Verify host. SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); EXPECT_EQ(0u, fake_delegate()->num_existing_user_host_switched_events_handled()); } TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest, + OnlyVerifiedHostCausesHostSwitchedEvent) { + BuildAccountStatusChangeDelegateNotifier(); + SetAccountStatusChangeDelegatePtr(); + // Set initially verified host. + SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); + + EXPECT_EQ(0u, + fake_delegate()->num_existing_user_host_switched_events_handled()); + + // Set a new host without verifying. + SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, + cryptauth::RemoteDeviceRefBuilder() + .SetPublicKey(kFakePhoneKey + "A") + .SetName(kFakePhoneName + "A") + .Build()); + EXPECT_EQ(0u, + fake_delegate()->num_existing_user_host_switched_events_handled()); + + // Set a different new host without confirming with backend so host is + // unverified. + SetHostWithStatus( + mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation, + cryptauth::RemoteDeviceRefBuilder() + .SetPublicKey(kFakePhoneKey + "B") + .SetName(kFakePhoneName + "B") + .Build()); + EXPECT_EQ(0u, + fake_delegate()->num_existing_user_host_switched_events_handled()); +} + +TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest, + ForgettingAndThenSwitchingHostsDoesNotTriggerHostSwitchedEvent) { + BuildAccountStatusChangeDelegateNotifier(); + SetAccountStatusChangeDelegatePtr(); + // Set initially verified host. + SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); + + EXPECT_EQ(0u, + fake_delegate()->num_existing_user_host_switched_events_handled()); + + // Forget host. + SetHostWithStatus(mojom::HostStatus::kEligibleHostExistsButNoHostSet, + base::nullopt /* host_device */); + EXPECT_EQ(0u, + fake_delegate()->num_existing_user_host_switched_events_handled()); + + // Set a new verified host. + SetHostWithStatus(mojom::HostStatus::kHostVerified, + cryptauth::RemoteDeviceRefBuilder() + .SetPublicKey(kFakePhoneKey + "alternate") + .SetName(kFakePhoneName + "alternate") + .Build()); + EXPECT_EQ(0u, + fake_delegate()->num_existing_user_host_switched_events_handled()); +} + +TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest, HostSwitchedBetweenSessions) { SetHostFromPreviousSession(kFakePhoneKey + "-old"); BuildAccountStatusChangeDelegateNotifier(); - // Host switched between sessions. + // Host switched and verified between sessions. SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); SetAccountStatusChangeDelegatePtr(); EXPECT_EQ(1u, @@ -312,7 +376,7 @@ // No enabled host initially. SetHostWithStatus(mojom::HostStatus::kEligibleHostExistsButNoHostSet, base::nullopt /* host_device */); - // Set host. + // Set and verify host. SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); EXPECT_EQ(0u, fake_delegate()->num_existing_user_host_switched_events_handled()); @@ -321,7 +385,7 @@ TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest, NoHostSwitchedEventWithoutObserverSet) { BuildAccountStatusChangeDelegateNotifier(); - // Set initial host. + // Set initially verified host. SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); // All conditions for host switched event are satisfied except for setting a // delegate. @@ -338,20 +402,66 @@ NotifiesObserverForChromebookAddedEvents) { BuildAccountStatusChangeDelegateNotifier(); SetAccountStatusChangeDelegatePtr(); - // Verify the delegate initializes to 0. + // Check the delegate initializes to 0. EXPECT_EQ( 0u, fake_delegate()->num_existing_user_chromebook_added_events_handled()); - // Host is set from another Chromebook while this one is logged in. + // Host is set and verified from another Chromebook while this one is logged + // in. SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); EXPECT_EQ( 1u, fake_delegate()->num_existing_user_chromebook_added_events_handled()); } TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest, + OnlyVerifiedHostCausesChromebookAddedEvent) { + BuildAccountStatusChangeDelegateNotifier(); + SetAccountStatusChangeDelegatePtr(); + // Start with potential hosts but none set. + SetHostWithStatus(mojom::HostStatus::kEligibleHostExistsButNoHostSet, + base::nullopt /* host_device */); + + // Set a host without verifying. + SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, kFakePhone); + EXPECT_EQ( + 0u, fake_delegate()->num_existing_user_chromebook_added_events_handled()); + + // Verify the new host. + SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); + EXPECT_EQ( + 1u, fake_delegate()->num_existing_user_chromebook_added_events_handled()); +} + +TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest, + ReplacingUnverifiedHostAWithVerifiedHostBCausesChromebookAddedEvent) { + BuildAccountStatusChangeDelegateNotifier(); + SetAccountStatusChangeDelegatePtr(); + // Start with potential hosts but none set. + // Set initial host but do not verify. + SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, + cryptauth::RemoteDeviceRefBuilder() + .SetPublicKey(kFakePhoneKey + "A") + .SetName(kFakePhoneName + "A") + .Build()); + + // Replace unverified Phone A with verified Phone B. + SetHostWithStatus(mojom::HostStatus::kHostVerified, + cryptauth::RemoteDeviceRefBuilder() + .SetPublicKey(kFakePhoneKey + "B") + .SetName(kFakePhoneName + "B") + .Build()); + // This causes a 'Chromebook added' event. + EXPECT_EQ( + 1u, fake_delegate()->num_existing_user_chromebook_added_events_handled()); + // It does not cause a 'host switched' event. + EXPECT_EQ(0u, + fake_delegate()->num_existing_user_host_switched_events_handled()); +} + +TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest, ChromebookAddedBetweenSessionsTriggersEvents) { BuildAccountStatusChangeDelegateNotifier(); - // Host is set before this Chromebook is logged in. + // Host is set and verified before this Chromebook is logged in. SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); SetAccountStatusChangeDelegatePtr(); @@ -387,6 +497,40 @@ 0u, fake_delegate()->num_existing_user_chromebook_added_events_handled()); } +TEST_F(MultiDeviceSetupAccountStatusChangeDelegateNotifierTest, + VerifiedHostIdStaysUpToDateInPrefs) { + BuildAccountStatusChangeDelegateNotifier(); + SetAccountStatusChangeDelegatePtr(); + // Check the delegate initializes to empty. + EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), ""); + + // Set initially verified host. + SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhone); + EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), kFakePhone.GetDeviceId()); + + const cryptauth::RemoteDeviceRef kFakePhoneAlternate = + cryptauth::RemoteDeviceRefBuilder() + .SetPublicKey(kFakePhoneKey + "alternate") + .SetName(kFakePhoneName + "alternate") + .Build(); + + // Switch to an unverified host. + SetHostWithStatus(mojom::HostStatus::kHostSetButNotYetVerified, + kFakePhoneAlternate); + // The host is set but not verified so the pref should be set to empty. + EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), ""); + + // Verify the new host. + SetHostWithStatus(mojom::HostStatus::kHostVerified, kFakePhoneAlternate); + EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), + kFakePhoneAlternate.GetDeviceId()); + + // Forget host. + SetHostWithStatus(mojom::HostStatus::kEligibleHostExistsButNoHostSet, + base::nullopt /* host_device */); + EXPECT_EQ(GetMostRecentVerifiedHostDeviceIdPref(), ""); +} + } // namespace multidevice_setup } // namespace chromeos
diff --git a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc index 13eca47..dc148ec 100644 --- a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc +++ b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
@@ -45,7 +45,7 @@ int timeout_ms = proto_.wait_for_dom().timeout_ms(); if (timeout_ms > 0) - check_rounds = std::min( + check_rounds = std::max( 1, static_cast<int>(std::ceil(timeout_ms / kCheckPeriodInMilliseconds)));
diff --git a/components/download/internal/common/download_response_handler.cc b/components/download/internal/common/download_response_handler.cc index 5921bf4..4523b77 100644 --- a/components/download/internal/common/download_response_handler.cc +++ b/components/download/internal/common/download_response_handler.cc
@@ -220,9 +220,10 @@ return; } - // OnComplete() called without OnReceiveResponse(). This should only + // OnComplete() called without OnResponseStarted(). This should only // happen when the request was aborted. - create_info_ = CreateDownloadCreateInfo(network::ResourceResponseHead()); + if (!create_info_) + create_info_ = CreateDownloadCreateInfo(network::ResourceResponseHead()); create_info_->result = reason; OnResponseStarted(mojom::DownloadStreamHandlePtr());
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc index 2186aa3..0c32c268 100644 --- a/components/exo/client_controlled_shell_surface_unittest.cc +++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -20,8 +20,8 @@ #include "ash/wm/drag_window_resizer.h" #include "ash/wm/overview/window_selector_controller.h" #include "ash/wm/splitview/split_view_controller.h" -#include "ash/wm/tablet_mode/tablet_mode_app_window_drag_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" +#include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h" #include "ash/wm/window_positioning_utils.h" #include "ash/wm/window_resizer.h" #include "ash/wm/window_state.h" @@ -1171,8 +1171,7 @@ const base::TimeDelta duration = event_generator->CalculateScrollDurationForFlingVelocity( start, end, - ash::TabletModeAppWindowDragController::kFlingToOverviewThreshold + - 10.f, + ash::TabletModeWindowDragDelegate::kFlingToOverviewThreshold + 10.f, 200); event_generator->GestureScrollSequence(start, end, duration, 200); EXPECT_TRUE(shell->window_selector_controller()->IsSelecting());
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc index d337f34..a984418 100644 --- a/components/exo/wayland/server.cc +++ b/components/exo/wayland/server.cc
@@ -2674,9 +2674,7 @@ const gfx::Rect& bounds = display.bounds(); const gfx::Insets& insets = display.GetWorkAreaInsets(); - double device_scale_factor = WMHelper::GetInstance() - ->GetDisplayInfo(display.id()) - .device_scale_factor(); + double device_scale_factor = display.device_scale_factor(); uint32_t display_id_hi = static_cast<uint32_t>(display.id() >> 32); uint32_t display_id_lo = static_cast<uint32_t>(display.id());
diff --git a/components/history/core/browser/history_database.cc b/components/history/core/browser/history_database.cc index c393b4a..d062389 100644 --- a/components/history/core/browser/history_database.cc +++ b/components/history/core/browser/history_database.cc
@@ -257,12 +257,15 @@ std::max(base::Time::Now() - base::TimeDelta::FromDays(30), base::Time()); sql::Statement url_sql(db_.GetUniqueStatement( - "SELECT u.url, u.visit_count " + "SELECT u.url, COUNT(u.id) " "FROM urls u JOIN visits v ON u.id = v.url " - "WHERE last_visit_time > ? " - "AND (v.transition & ?) != 0 " // CHAIN_END - "AND (transition & ?) NOT IN (?, ?, ?)")); // NO SUBFRAME or - // KEYWORD_GENERATED + "WHERE v.visit_time > ? " + "AND (v.transition & ?) != 0 " // CHAIN_END + "AND (v.transition & ?) NOT IN (?, ?, ?, ?) " // NO SUBFRAME or + // KEYWORD_GENERATED or + // RELOAD + "GROUP BY u.url " + "ORDER BY u.last_visit_time DESC")); url_sql.BindInt64(0, one_month_ago.ToInternalValue()); url_sql.BindInt(1, ui::PAGE_TRANSITION_CHAIN_END); @@ -270,6 +273,7 @@ url_sql.BindInt(3, ui::PAGE_TRANSITION_AUTO_SUBFRAME); url_sql.BindInt(4, ui::PAGE_TRANSITION_MANUAL_SUBFRAME); url_sql.BindInt(5, ui::PAGE_TRANSITION_KEYWORD_GENERATED); + url_sql.BindInt(6, ui::PAGE_TRANSITION_RELOAD); // Collect a map from host to visit count. base::hash_map<std::string, int> host_count; @@ -278,14 +282,20 @@ if (!(url.is_valid() && (url.SchemeIsHTTPOrHTTPS() || url.SchemeIs("ftp")))) continue; - int64_t visit_count = url_sql.ColumnInt64(1); - host_count[HostForTopHosts(url)] += visit_count; + std::string host_for_top_host = HostForTopHosts(url); // kMaxHostsInMemory is well above typical values for - // History.MonthlyHostCount, but here to guard against unbounded memory + // History.MonthlyHostCount, but is used to guard against unbounded memory // growth in the event of an atypical history. - if (host_count.size() >= kMaxHostsInMemory) - break; + // Continue in the case where the host limit is reached and this is a newly + // encountered host that would add an additional entry to the map. + if (host_count.size() >= kMaxHostsInMemory && + host_count.find(host_for_top_host) == host_count.end()) { + continue; + } + + int64_t visit_count = url_sql.ColumnInt64(1); + host_count[host_for_top_host] += visit_count; } // Collect the top 100 hosts by visit count, into the range
diff --git a/components/history/core/browser/history_service_unittest.cc b/components/history/core/browser/history_service_unittest.cc index 6790a486..c92c899 100644 --- a/components/history/core/browser/history_service_unittest.cc +++ b/components/history/core/browser/history_service_unittest.cc
@@ -21,6 +21,9 @@ #include <stdint.h> +#include <algorithm> +#include <string> + #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/location.h" @@ -58,11 +61,6 @@ ~HistoryServiceTest() override {} - void OnMostVisitedURLsAvailable(const MostVisitedURLList* url_list) { - most_visited_urls_ = *url_list; - base::RunLoop::QuitCurrentWhenIdleDeprecated(); - } - protected: friend class BackendDelegate; @@ -140,8 +138,8 @@ base::RunLoop run_loop; history_service_->QueryRedirectsFrom( url, - base::Bind(&HistoryServiceTest::OnRedirectQueryComplete, - base::Unretained(this), run_loop.QuitClosure()), + base::BindRepeating(&HistoryServiceTest::OnRedirectQueryComplete, + base::Unretained(this), run_loop.QuitClosure()), &tracker_); run_loop.Run(); // Will be exited in *QueryComplete. } @@ -157,11 +155,48 @@ std::move(done).Run(); } + void QueryMostVisitedURLs() { + const int kResultCount = 20; + const int kDaysBack = 90; + + base::RunLoop run_loop; + history_service_->QueryMostVisitedURLs( + kResultCount, kDaysBack, + base::BindRepeating(&HistoryServiceTest::OnQueryMostVisitedURLsComplete, + base::Unretained(this), run_loop.QuitClosure()), + &tracker_); + run_loop.Run(); // Will be exited in *QueryComplete. + } + + void OnQueryMostVisitedURLsComplete(base::OnceClosure done, + const MostVisitedURLList* url_list) { + most_visited_urls_ = *url_list; + std::move(done).Run(); + } + + void GetTopHosts() { + const int kNumHosts = 20; + + base::RunLoop run_loop; + history_service_->TopHosts( + kNumHosts, + base::BindRepeating(&HistoryServiceTest::OnTopHostsComplete, + base::Unretained(this), run_loop.QuitClosure())); + run_loop.Run(); // Will be exited in *QueryComplete. + } + + void OnTopHostsComplete(base::OnceClosure done, + const TopHostsList& top_hosts_list) { + top_hosts_list_ = top_hosts_list; + std::move(done).Run(); + } + base::ScopedTempDir temp_dir_; base::test::ScopedTaskEnvironment scoped_task_environment_; MostVisitedURLList most_visited_urls_; + TopHostsList top_hosts_list_; // When non-NULL, this will be deleted on tear down and we will block until // the backend thread has completed. This allows tests for the history @@ -499,13 +534,8 @@ url1, base::Time::Now(), context_id, 0, GURL(), history::RedirectList(), ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, false); - history_service_->QueryMostVisitedURLs( - 20, - 90, - base::Bind(&HistoryServiceTest::OnMostVisitedURLsAvailable, - base::Unretained(this)), - &tracker_); - base::RunLoop().Run(); + + QueryMostVisitedURLs(); EXPECT_EQ(2U, most_visited_urls_.size()); EXPECT_EQ(url0, most_visited_urls_[0].url); @@ -516,13 +546,8 @@ url2, base::Time::Now(), context_id, 0, GURL(), history::RedirectList(), ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, false); - history_service_->QueryMostVisitedURLs( - 20, - 90, - base::Bind(&HistoryServiceTest::OnMostVisitedURLsAvailable, - base::Unretained(this)), - &tracker_); - base::RunLoop().Run(); + + QueryMostVisitedURLs(); EXPECT_EQ(3U, most_visited_urls_.size()); EXPECT_EQ(url0, most_visited_urls_[0].url); @@ -534,13 +559,8 @@ url2, base::Time::Now(), context_id, 0, GURL(), history::RedirectList(), ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, false); - history_service_->QueryMostVisitedURLs( - 20, - 90, - base::Bind(&HistoryServiceTest::OnMostVisitedURLsAvailable, - base::Unretained(this)), - &tracker_); - base::RunLoop().Run(); + + QueryMostVisitedURLs(); EXPECT_EQ(3U, most_visited_urls_.size()); EXPECT_EQ(url2, most_visited_urls_[0].url); @@ -552,13 +572,8 @@ url1, base::Time::Now(), context_id, 0, GURL(), history::RedirectList(), ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, false); - history_service_->QueryMostVisitedURLs( - 20, - 90, - base::Bind(&HistoryServiceTest::OnMostVisitedURLsAvailable, - base::Unretained(this)), - &tracker_); - base::RunLoop().Run(); + + QueryMostVisitedURLs(); EXPECT_EQ(3U, most_visited_urls_.size()); EXPECT_EQ(url1, most_visited_urls_[0].url); @@ -571,13 +586,8 @@ url4, base::Time::Now(), context_id, 0, GURL(), redirects, ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, false); - history_service_->QueryMostVisitedURLs( - 20, - 90, - base::Bind(&HistoryServiceTest::OnMostVisitedURLsAvailable, - base::Unretained(this)), - &tracker_); - base::RunLoop().Run(); + + QueryMostVisitedURLs(); EXPECT_EQ(4U, most_visited_urls_.size()); EXPECT_EQ(url1, most_visited_urls_[0].url); @@ -587,6 +597,104 @@ EXPECT_EQ(2U, most_visited_urls_[3].redirects.size()); } +TEST_F(HistoryServiceTest, TopHosts) { + ASSERT_TRUE(history_service_.get()); + + const std::string top_host0_espn_host_name = "espn.com"; + const std::string top_host1_google_host_name = "google.com"; + const std::string top_host2_cnn_host_name = "cnn.com"; + + const int top_host0_espn_host_count = 4; + const int top_host1_google_host_count = 3; + const int top_host2_cnn_host_count = 2; + + const GURL url0_espn0("http://www.espn.com/"); + const GURL url1_google0("http://www.google.com/url1/google0"); + const GURL url2_google1("http://www.google.com/url2/google1"); + const GURL url3_google2("http://www.google.com/url3/google2"); + const GURL url4_espn1("http://www.espn.com/"); + const GURL url5_cnn0("http://www.cnn.com/url5/cnn0"); + const GURL url6_espn2("http://www.espn.com/"); + const GURL url7_cnn1("http://www.cnn.com/url7/cnn1"); + const GURL url8_espn3("http://www.espn.com/"); + + const GURL url9_espn4_expired("http://www.espn.com/"); + const GURL url10_google3_expired("http://www.espn.com/url10/google3"); + + const GURL url11_espn5_reload("http://www.espn.com/"); + const GURL url12_google4_reload("http://www.espn.com/url12/google4"); + + const ContextID context_id = reinterpret_cast<ContextID>(1); + + // Add unexpired pages. + history_service_->AddPage(url0_espn0, base::Time::Now(), context_id, 0, + GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, + false); + history_service_->AddPage(url1_google0, base::Time::Now(), context_id, 0, + GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, + false); + history_service_->AddPage(url2_google1, base::Time::Now(), context_id, 0, + GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, + false); + history_service_->AddPage(url3_google2, base::Time::Now(), context_id, 0, + GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, + false); + history_service_->AddPage(url4_espn1, base::Time::Now(), context_id, 0, + GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, + false); + history_service_->AddPage(url5_cnn0, base::Time::Now(), context_id, 0, GURL(), + history::RedirectList(), ui::PAGE_TRANSITION_TYPED, + history::SOURCE_BROWSED, false); + history_service_->AddPage(url6_espn2, base::Time::Now(), context_id, 0, + GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, + false); + history_service_->AddPage(url7_cnn1, base::Time::Now(), context_id, 0, GURL(), + history::RedirectList(), ui::PAGE_TRANSITION_TYPED, + history::SOURCE_BROWSED, false); + history_service_->AddPage(url8_espn3, base::Time::Now(), context_id, 0, + GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, + false); + + // Add expired pages. + base::Time thirty_one_days_ago = + std::max(base::Time::Now() - base::TimeDelta::FromDays(31), base::Time()); + history_service_->AddPage(url9_espn4_expired, thirty_one_days_ago, context_id, + 0, GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, + false); + history_service_->AddPage(url10_google3_expired, thirty_one_days_ago, + context_id, 0, GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, + false); + + // Add reload pages. + history_service_->AddPage(url11_espn5_reload, base::Time::Now(), context_id, + 0, GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_RELOAD, history::SOURCE_BROWSED, + false); + history_service_->AddPage(url12_google4_reload, base::Time::Now(), context_id, + 0, GURL(), history::RedirectList(), + ui::PAGE_TRANSITION_RELOAD, history::SOURCE_BROWSED, + false); + + GetTopHosts(); + + ASSERT_EQ(3U, top_hosts_list_.size()); + EXPECT_EQ(top_host0_espn_host_name, top_hosts_list_[0].first); + EXPECT_EQ(top_host1_google_host_name, top_hosts_list_[1].first); + EXPECT_EQ(top_host2_cnn_host_name, top_hosts_list_[2].first); + EXPECT_EQ(top_host0_espn_host_count, top_hosts_list_[0].second); + EXPECT_EQ(top_host1_google_host_count, top_hosts_list_[1].second); + EXPECT_EQ(top_host2_cnn_host_count, top_hosts_list_[2].second); +} + namespace { // A HistoryDBTask implementation. Each time RunOnDBThread is invoked
diff --git a/components/ntp_tiles/custom_links_manager.h b/components/ntp_tiles/custom_links_manager.h index 99ef677..df527c1f 100644 --- a/components/ntp_tiles/custom_links_manager.h +++ b/components/ntp_tiles/custom_links_manager.h
@@ -26,7 +26,7 @@ // modifies the link, it will no longer be considered Most Visited and will not // be deleted when history is cleared. // -// TODO(crbug/861831): Add Chrome sync support. +// The current list of links is kept in sync with any changes from Chrome sync. class CustomLinksManager { public: struct Link { @@ -80,7 +80,7 @@ // Registers a callback that will be invoked when custom links are updated by // sources other than this interface's methods (i.e. when links are deleted by - // history clear). + // history clear or when links are updated by Chrome sync). virtual std::unique_ptr<base::CallbackList<void()>::Subscription> RegisterCallbackForOnChanged(base::RepeatingClosure callback) = 0; };
diff --git a/components/ntp_tiles/custom_links_manager_impl.cc b/components/ntp_tiles/custom_links_manager_impl.cc index d0a6150..e59b77ec 100644 --- a/components/ntp_tiles/custom_links_manager_impl.cc +++ b/components/ntp_tiles/custom_links_manager_impl.cc
@@ -8,6 +8,7 @@ #include <string> #include <utility> +#include "base/auto_reset.h" #include "components/ntp_tiles/pref_names.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" @@ -32,6 +33,13 @@ history_service_observer_.Add(history_service); if (IsInitialized()) current_links_ = store_.RetrieveLinks(); + + base::RepeatingClosure callback = + base::BindRepeating(&CustomLinksManagerImpl::OnPreferenceChanged, + weak_ptr_factory_.GetWeakPtr()); + pref_change_registrar_.Init(prefs_); + pref_change_registrar_.Add(prefs::kCustomLinksInitialized, callback); + pref_change_registrar_.Add(prefs::kCustomLinksList, callback); } CustomLinksManagerImpl::~CustomLinksManagerImpl() = default; @@ -43,14 +51,20 @@ for (const NTPTile& tile : tiles) current_links_.emplace_back(Link{tile.url, tile.title, true}); - store_.StoreLinks(current_links_); - prefs_->SetBoolean(prefs::kCustomLinksInitialized, true); + { + base::AutoReset<bool> auto_reset(&updating_preferences_, true); + prefs_->SetBoolean(prefs::kCustomLinksInitialized, true); + } + StoreLinks(); return true; } void CustomLinksManagerImpl::Uninitialize() { + { + base::AutoReset<bool> auto_reset(&updating_preferences_, true); + prefs_->SetBoolean(prefs::kCustomLinksInitialized, false); + } ClearLinks(); - prefs_->SetBoolean(prefs::kCustomLinksInitialized, false); } bool CustomLinksManagerImpl::IsInitialized() const { @@ -74,7 +88,7 @@ previous_links_ = current_links_; current_links_.emplace_back(Link{url, title, false}); - store_.StoreLinks(current_links_); + StoreLinks(); return true; } @@ -106,7 +120,7 @@ it->title = new_title; it->is_most_visited = false; - store_.StoreLinks(current_links_); + StoreLinks(); return true; } @@ -120,7 +134,7 @@ previous_links_ = current_links_; current_links_.erase(it); - store_.StoreLinks(current_links_); + StoreLinks(); return true; } @@ -131,16 +145,24 @@ // Replace the current links with the previous state. current_links_ = *previous_links_; previous_links_ = base::nullopt; - store_.StoreLinks(current_links_); + StoreLinks(); return true; } void CustomLinksManagerImpl::ClearLinks() { - store_.ClearLinks(); + { + base::AutoReset<bool> auto_reset(&updating_preferences_, true); + store_.ClearLinks(); + } current_links_.clear(); previous_links_ = base::nullopt; } +void CustomLinksManagerImpl::StoreLinks() { + base::AutoReset<bool> auto_reset(&updating_preferences_, true); + store_.StoreLinks(current_links_); +} + std::vector<CustomLinksManager::Link>::iterator CustomLinksManagerImpl::FindLinkWithUrl(const GURL& url) { return std::find_if(current_links_.begin(), current_links_.end(), @@ -172,7 +194,7 @@ current_links_.erase(it); } } - store_.StoreLinks(current_links_); + StoreLinks(); previous_links_ = base::nullopt; // Alert MostVisitedSites that some links have been deleted. @@ -185,10 +207,24 @@ history_service_observer_.RemoveAll(); } +void CustomLinksManagerImpl::OnPreferenceChanged() { + if (updating_preferences_) + return; + + if (IsInitialized()) + current_links_ = store_.RetrieveLinks(); + else + current_links_.clear(); + previous_links_ = base::nullopt; + callback_list_.Notify(); +} + // static void CustomLinksManagerImpl::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* user_prefs) { - user_prefs->RegisterBooleanPref(prefs::kCustomLinksInitialized, false); + user_prefs->RegisterBooleanPref( + prefs::kCustomLinksInitialized, false, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); CustomLinksStore::RegisterProfilePrefs(user_prefs); }
diff --git a/components/ntp_tiles/custom_links_manager_impl.h b/components/ntp_tiles/custom_links_manager_impl.h index 20e2c59..cc5902b 100644 --- a/components/ntp_tiles/custom_links_manager_impl.h +++ b/components/ntp_tiles/custom_links_manager_impl.h
@@ -17,6 +17,7 @@ #include "components/ntp_tiles/custom_links_manager.h" #include "components/ntp_tiles/custom_links_store.h" #include "components/ntp_tiles/ntp_tile.h" +#include "components/prefs/pref_change_registrar.h" class PrefService; @@ -60,6 +61,11 @@ private: void ClearLinks(); + + // Stores the current list to the profile's preferences. Does not notify + // |OnPreferenceChanged|. + void StoreLinks(); + // Returns an iterator into |custom_links_|. std::vector<Link>::iterator FindLinkWithUrl(const GURL& url); @@ -71,6 +77,11 @@ void HistoryServiceBeingDeleted( history::HistoryService* history_service) override; + // Called when the current list of links and/or initialization state in + // PrefService is modified. Saves the new set of links in |current_links_| + // and notifies |callback_list_|. + void OnPreferenceChanged(); + PrefService* const prefs_; CustomLinksStore store_; std::vector<Link> current_links_; @@ -86,6 +97,13 @@ ScopedObserver<history::HistoryService, history::HistoryServiceObserver> history_service_observer_; + // Observer for Chrome sync changes to |prefs::kCustomLinksList| and + // |prefs::kCustomLinksInitialized|. + PrefChangeRegistrar pref_change_registrar_; + // Used to ignore notifications from |pref_change_registrar_| that we trigger + // ourselves when updating the preferences. + bool updating_preferences_ = false; + base::WeakPtrFactory<CustomLinksManagerImpl> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(CustomLinksManagerImpl);
diff --git a/components/ntp_tiles/custom_links_manager_impl_unittest.cc b/components/ntp_tiles/custom_links_manager_impl_unittest.cc index b70c124..bf54bfc 100644 --- a/components/ntp_tiles/custom_links_manager_impl_unittest.cc +++ b/components/ntp_tiles/custom_links_manager_impl_unittest.cc
@@ -13,6 +13,7 @@ #include "base/test/mock_callback.h" #include "base/test/scoped_task_environment.h" #include "components/history/core/test/history_service_test_util.h" +#include "components/ntp_tiles/pref_names.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "testing/gtest/include/gtest/gtest.h" @@ -44,6 +45,16 @@ const char kTestTitle[] = "Test"; const char kTestUrl[] = "http://test.com/"; +base::Value::ListStorage FillTestListStorage(const char* url, + const char* title) { + base::Value::ListStorage new_link_list; + base::DictionaryValue new_link; + new_link.SetKey("url", base::Value(url)); + new_link.SetKey("title", base::Value(title)); + new_link_list.push_back(std::move(new_link)); + return new_link_list; +} + void AddTile(NTPTilesVector* tiles, const char* url, const char* title) { NTPTile tile; tile.url = GURL(url); @@ -602,4 +613,114 @@ scoped_task_environment_.RunUntilIdle(); } +TEST_F(CustomLinksManagerImplTest, UpdateListAfterRemoteChange) { + Link remote_link{GURL(kTestUrl), base::UTF8ToUTF16(kTestTitle), false}; + NTPTilesVector initial_tiles; + std::vector<Link> initial_links; + std::vector<Link> links_after_add = FillTestLinks(kTestCase1); + links_after_add[0].is_most_visited = false; + std::vector<Link> remote_links; + remote_links.emplace_back(remote_link); + + // Set up Most Visited callback. + base::MockCallback<base::RepeatingClosure> callback; + std::unique_ptr<base::CallbackList<void()>::Subscription> subscription = + custom_links_->RegisterCallbackForOnChanged(callback.Get()); + + // Initialize. + ASSERT_TRUE(custom_links_->Initialize(initial_tiles)); + ASSERT_EQ(initial_links, custom_links_->GetLinks()); + + // Modifying ourselves should not notify. + EXPECT_CALL(callback, Run()).Times(0); + EXPECT_TRUE(custom_links_->AddLink(GURL(kTestCase1[0].url), + base::UTF8ToUTF16(kTestCase1[0].title))); + EXPECT_EQ(links_after_add, custom_links_->GetLinks()); + + // Modify the preference. This should notify and update the current list of + // links. + EXPECT_CALL(callback, Run()); + prefs_.SetUserPref( + prefs::kCustomLinksList, + std::make_unique<base::Value>(FillTestListStorage(kTestUrl, kTestTitle))); + EXPECT_EQ(remote_links, custom_links_->GetLinks()); +} + +TEST_F(CustomLinksManagerImplTest, InitializeListAfterRemoteChange) { + Link remote_link{GURL(kTestUrl), base::UTF8ToUTF16(kTestTitle), false}; + NTPTilesVector initial_tiles; + std::vector<Link> initial_links; + std::vector<Link> remote_links(initial_links); + remote_links.emplace_back(remote_link); + + // Set up Most Visited callback. + base::MockCallback<base::RepeatingClosure> callback; + std::unique_ptr<base::CallbackList<void()>::Subscription> subscription = + custom_links_->RegisterCallbackForOnChanged(callback.Get()); + + ASSERT_FALSE(custom_links_->IsInitialized()); + + // Modify the preference. This should notify and initialize custom links. + EXPECT_CALL(callback, Run()).Times(2); + prefs_.SetUserPref(prefs::kCustomLinksInitialized, + std::make_unique<base::Value>(true)); + prefs_.SetUserPref( + prefs::kCustomLinksList, + std::make_unique<base::Value>(FillTestListStorage(kTestUrl, kTestTitle))); + EXPECT_TRUE(custom_links_->IsInitialized()); + EXPECT_EQ(remote_links, custom_links_->GetLinks()); +} + +TEST_F(CustomLinksManagerImplTest, UninitializeListAfterRemoteChange) { + NTPTilesVector initial_tiles = FillTestTiles(kTestCase1); + std::vector<Link> initial_links = FillTestLinks(kTestCase1); + std::vector<Link> remote_links; + + // Set up Most Visited callback. + base::MockCallback<base::RepeatingClosure> callback; + std::unique_ptr<base::CallbackList<void()>::Subscription> subscription = + custom_links_->RegisterCallbackForOnChanged(callback.Get()); + + // Initialize. + ASSERT_TRUE(custom_links_->Initialize(initial_tiles)); + ASSERT_EQ(initial_links, custom_links_->GetLinks()); + + // Modify the preference. This should notify and uninitialize custom links. + EXPECT_CALL(callback, Run()).Times(2); + prefs_.SetUserPref(prefs::kCustomLinksInitialized, + std::make_unique<base::Value>(false)); + prefs_.SetUserPref(prefs::kCustomLinksList, + std::make_unique<base::Value>(base::Value::ListStorage())); + EXPECT_FALSE(custom_links_->IsInitialized()); + EXPECT_EQ(remote_links, custom_links_->GetLinks()); +} + +TEST_F(CustomLinksManagerImplTest, ClearThenUninitializeListAfterRemoteChange) { + NTPTilesVector initial_tiles = FillTestTiles(kTestCase1); + std::vector<Link> initial_links = FillTestLinks(kTestCase1); + std::vector<Link> remote_links; + + // Set up Most Visited callback. + base::MockCallback<base::RepeatingClosure> callback; + std::unique_ptr<base::CallbackList<void()>::Subscription> subscription = + custom_links_->RegisterCallbackForOnChanged(callback.Get()); + + // Initialize. + ASSERT_TRUE(custom_links_->Initialize(initial_tiles)); + ASSERT_EQ(initial_links, custom_links_->GetLinks()); + + // Modify the preference. Simulates when the list preference is synced before + // the initialized preference. This should notify and uninitialize custom + // links. + EXPECT_CALL(callback, Run()).Times(2); + prefs_.SetUserPref(prefs::kCustomLinksList, + std::make_unique<base::Value>(base::Value::ListStorage())); + EXPECT_TRUE(custom_links_->IsInitialized()); + EXPECT_EQ(remote_links, custom_links_->GetLinks()); + prefs_.SetUserPref(prefs::kCustomLinksInitialized, + std::make_unique<base::Value>(false)); + EXPECT_FALSE(custom_links_->IsInitialized()); + EXPECT_EQ(remote_links, custom_links_->GetLinks()); +} + } // namespace ntp_tiles
diff --git a/components/ntp_tiles/custom_links_store.cc b/components/ntp_tiles/custom_links_store.cc index 84211f41..53f38616 100644 --- a/components/ntp_tiles/custom_links_store.cc +++ b/components/ntp_tiles/custom_links_store.cc
@@ -71,7 +71,8 @@ // static void CustomLinksStore::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* user_prefs) { - user_prefs->RegisterListPref(prefs::kCustomLinksList); + user_prefs->RegisterListPref(prefs::kCustomLinksList, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); } } // namespace ntp_tiles
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.h b/components/offline_pages/core/model/offline_page_model_taskified.h index 391d2beb..0d5dc55 100644 --- a/components/offline_pages/core/model/offline_page_model_taskified.h +++ b/components/offline_pages/core/model/offline_page_model_taskified.h
@@ -79,7 +79,6 @@ // OfflinePageModel implementation. void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; - void SavePage(const SavePageParams& save_page_params, std::unique_ptr<OfflinePageArchiver> archiver, content::WebContents* web_contents, @@ -108,10 +107,8 @@ MultipleOfflinePageItemCallback callback) override; void GetPagesByNamespace(const std::string& name_space, MultipleOfflinePageItemCallback callback) override; - // Get all pages in the namespaces that will be removed on cache reset. void GetPagesRemovedOnCacheReset( MultipleOfflinePageItemCallback callback) override; - // Get all pages in the namespaces that are shown in download ui. void GetPagesSupportedByDownloads( MultipleOfflinePageItemCallback callback) override; void GetPagesByRequestOrigin( @@ -130,16 +127,11 @@ void HasThumbnailForOfflineId( int64_t offline_id, base::OnceCallback<void(bool)> callback) override; - const base::FilePath& GetInternalArchiveDirectory( const std::string& name_space) const override; bool IsArchiveInInternalDir(const base::FilePath& file_path) const override; - ClientPolicyController* GetPolicyController() override; - OfflineEventLogger* GetLogger() override; - - // Publish an offline page from our internal directory to a public directory. void PublishInternalArchive( const OfflinePageItem& offline_page, std::unique_ptr<OfflinePageArchiver> archiver,
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc index 3c11e555..3bb7a0cc 100644 --- a/components/omnibox/browser/autocomplete_controller.cc +++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -512,12 +512,20 @@ i != providers_.end(); ++i) result_.AppendMatches(input_, (*i)->matches()); + if (OmniboxFieldTrial::GetPedalSuggestionMode() == + OmniboxFieldTrial::PedalSuggestionMode::DEDICATED) + result_.AppendDedicatedPedalMatches(provider_client_.get(), input_); + // Sort the matches and trim to a small number of "best" matches. result_.SortAndCull(input_, template_url_service_); if (OmniboxFieldTrial::IsTabSwitchSuggestionsEnabled()) result_.ConvertOpenTabMatches(provider_client_.get(), &input_); + if (OmniboxFieldTrial::GetPedalSuggestionMode() == + OmniboxFieldTrial::PedalSuggestionMode::IN_SUGGESTION) + result_.ConvertInSuggestionPedalMatches(provider_client_.get()); + // Need to validate before invoking CopyOldMatches as the old matches are not // valid against the current input. #if DCHECK_IS_ON()
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc index addc22e8..32314f6 100644 --- a/components/omnibox/browser/autocomplete_match.cc +++ b/components/omnibox/browser/autocomplete_match.cc
@@ -23,6 +23,7 @@ #include "components/omnibox/browser/autocomplete_provider.h" #include "components/omnibox/browser/buildflags.h" #include "components/omnibox/browser/omnibox_field_trial.h" +#include "components/omnibox/browser/omnibox_pedal.h" #include "components/omnibox/browser/suggestion_answer.h" #include "components/search_engines/template_url.h" #include "components/search_engines/template_url_service.h" @@ -143,6 +144,7 @@ ? new AutocompleteMatch(*match.associated_keyword) : nullptr), keyword(match.keyword), + pedal(match.pedal), from_previous(match.from_previous), search_terms_args( match.search_terms_args @@ -188,6 +190,7 @@ ? new AutocompleteMatch(*match.associated_keyword) : nullptr); keyword = match.keyword; + pedal = match.pedal; from_previous = match.from_previous; search_terms_args.reset( match.search_terms_args @@ -278,6 +281,9 @@ case Type::SEARCH_SUGGEST_TAIL: return omnibox::kBlankIcon; + case Type::PEDAL: + return omnibox::kPedalIcon; + case Type::NUM_TYPES: NOTREACHED(); break; @@ -683,6 +689,19 @@ return answer ? answer->image_url() : GURL(image_url); } +void AutocompleteMatch::ApplyPedal() { + type = Type::PEDAL; + contents = pedal->GetLabelStrings().suggestion_contents; + destination_url = pedal->GetNavigationUrl(); + + // Normally this is computed by the match using a TemplateURLService + // but Pedal URLs are not typical and unknown, and we don't want them to + // be deduped, e.g. after stripping a query parameter that may do something + // meaningful like indicate the viewable scope of a settings page. So here + // we keep the URL exactly as the Pedal specifies it. + stripped_destination_url = destination_url; +} + void AutocompleteMatch::RecordAdditionalInfo(const std::string& property, const std::string& value) { DCHECK(!property.empty()); @@ -789,7 +808,11 @@ } bool AutocompleteMatch::ShouldShowTabMatch() const { - return has_tab_match && !associated_keyword; + // TODO(orinj): If side button Pedal presentation mode is not kept, + // the simpler logic (with no pedal checks) can be restored, and if it is + // kept then some minor refactoring (or at least renaming) is in order. + return (has_tab_match && !associated_keyword) || + (pedal && pedal->ShouldPresentButton()); } #if DCHECK_IS_ON()
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h index 5b348fe..a2c987d 100644 --- a/components/omnibox/browser/autocomplete_match.h +++ b/components/omnibox/browser/autocomplete_match.h
@@ -23,6 +23,7 @@ #include "url/gurl.h" class AutocompleteProvider; +class OmniboxPedal; class SuggestionAnswer; class TemplateURL; class TemplateURLService; @@ -303,6 +304,9 @@ // there isn't an image URL, returns an empty GURL (test with is_empty()). GURL ImageUrl() const; + // Changes properties to make use of the Pedal (e.g. content, URLs...). + void ApplyPedal(); + // Adds optional information to the |additional_info| dictionary. void RecordAdditionalInfo(const std::string& property, const std::string& value); @@ -477,6 +481,10 @@ // it! base::string16 keyword; + // Set to a matching pedal if appropriate. The pedal is not owned, and the + // owning OmniboxPedalProvider must outlive this. + OmniboxPedal* pedal = nullptr; + // True if this match is from a previous result. bool from_previous;
diff --git a/components/omnibox/browser/autocomplete_match_type.cc b/components/omnibox/browser/autocomplete_match_type.cc index cd315dc..246ad99 100644 --- a/components/omnibox/browser/autocomplete_match_type.cc +++ b/components/omnibox/browser/autocomplete_match_type.cc
@@ -42,6 +42,7 @@ "physical-web-overflow", "tab-search", "document", + "pedal", }; // clang-format on static_assert(arraysize(strings) == AutocompleteMatchType::NUM_TYPES, @@ -125,6 +126,9 @@ 0, // PHYSICAL_WEB_OVERFLOW_DEPRECATED IDS_ACC_AUTOCOMPLETE_HISTORY, // TAB_SEARCH_DEPRECATED 0, // DOCUMENT_SUGGESTION + + // TODO(orinj): Determine appropriate accessibility labels for Pedals + 0, // PEDAL }; static_assert(arraysize(message_ids) == AutocompleteMatchType::NUM_TYPES, "message_ids must have NUM_TYPES elements");
diff --git a/components/omnibox/browser/autocomplete_match_type.h b/components/omnibox/browser/autocomplete_match_type.h index d9441d9..3f3af82 100644 --- a/components/omnibox/browser/autocomplete_match_type.h +++ b/components/omnibox/browser/autocomplete_match_type.h
@@ -64,6 +64,7 @@ TAB_SEARCH_DEPRECATED = 23, // A suggested open tab, based on its // URL or title, via HQP (deprecated). DOCUMENT_SUGGESTION = 24, // A suggested document. + PEDAL = 25, // An omnibox pedal suggestion. NUM_TYPES, }; // clang-format on
diff --git a/components/omnibox/browser/autocomplete_provider_client.h b/components/omnibox/browser/autocomplete_provider_client.h index 9bf2735..8f3cc36 100644 --- a/components/omnibox/browser/autocomplete_provider_client.h +++ b/components/omnibox/browser/autocomplete_provider_client.h
@@ -26,6 +26,7 @@ class GURL; class InMemoryURLIndex; class KeywordProvider; +class OmniboxPedalProvider; class PrefService; class ShortcutsBackend; @@ -64,6 +65,7 @@ bool create_if_necessary) const = 0; virtual DocumentSuggestionsService* GetDocumentSuggestionsService( bool create_if_necessary) const = 0; + virtual OmniboxPedalProvider* GetPedalProvider() const = 0; virtual scoped_refptr<ShortcutsBackend> GetShortcutsBackend() = 0; virtual scoped_refptr<ShortcutsBackend> GetShortcutsBackendIfExists() = 0; virtual std::unique_ptr<KeywordExtensionsDelegate>
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc index af578d6..742c670 100644 --- a/components/omnibox/browser/autocomplete_result.cc +++ b/components/omnibox/browser/autocomplete_result.cc
@@ -8,6 +8,7 @@ #include <functional> #include <iterator> #include <string> +#include <unordered_set> #include "base/command_line.h" #include "base/logging.h" @@ -22,6 +23,8 @@ #include "components/omnibox/browser/autocomplete_provider_client.h" #include "components/omnibox/browser/match_compare.h" #include "components/omnibox/browser/omnibox_field_trial.h" +#include "components/omnibox/browser/omnibox_pedal.h" +#include "components/omnibox/browser/omnibox_pedal_provider.h" #include "components/omnibox/browser/omnibox_switches.h" #include "components/strings/grit/components_strings.h" #include "components/url_formatter/url_fixer.h" @@ -226,6 +229,49 @@ GURL() : ComputeAlternateNavUrl(input, *default_match_); } +void AutocompleteResult::AppendDedicatedPedalMatches( + AutocompleteProviderClient* client, + const AutocompleteInput& input) { + ACMatches pedal_suggestions; + const OmniboxPedalProvider* provider = client->GetPedalProvider(); + for (const auto& match : matches_) { + if (match.pedal) + continue; + OmniboxPedal* pedal = provider->FindPedalMatch(match.contents); + if (pedal) { + AutocompleteMatch suggestion = match; + suggestion.relevance--; + suggestion.pedal = pedal; + suggestion.ApplyPedal(); + pedal_suggestions.push_back(suggestion); + } + } + if (!pedal_suggestions.empty()) { + AppendMatches(input, pedal_suggestions); + } +} + +void AutocompleteResult::ConvertInSuggestionPedalMatches( + AutocompleteProviderClient* client) { + const OmniboxPedalProvider* provider = client->GetPedalProvider(); + // Used to ensure we keep only one Pedal of each kind. + std::unordered_set<OmniboxPedal*> pedals_found; + for (auto& match : matches_) { + // Skip matches that will not show Pedal because they already + // have a tab match or associated keyword. Also skip matches + // that have already detected their Pedal. + if (match.has_tab_match || match.associated_keyword || match.pedal) + continue; + + OmniboxPedal* const pedal = provider->FindPedalMatch(match.contents); + if (pedal) { + const auto result = pedals_found.insert(pedal); + if (result.second) + match.pedal = pedal; + } + } +} + void AutocompleteResult::ConvertOpenTabMatches( AutocompleteProviderClient* client, const AutocompleteInput* input) { @@ -239,6 +285,7 @@ match.has_tab_match = true; } } + bool AutocompleteResult::HasCopiedMatches() const { for (auto i(begin()); i != end(); ++i) { if (i->from_previous)
diff --git a/components/omnibox/browser/autocomplete_result.h b/components/omnibox/browser/autocomplete_result.h index 06dfd23a..afd1841 100644 --- a/components/omnibox/browser/autocomplete_result.h +++ b/components/omnibox/browser/autocomplete_result.h
@@ -55,6 +55,13 @@ void SortAndCull(const AutocompleteInput& input, TemplateURLService* template_url_service); + // Creates and adds any dedicated Pedal matches triggered by existing match. + void AppendDedicatedPedalMatches(AutocompleteProviderClient* client, + const AutocompleteInput& input); + + // Sets |pedal| in matches that have Pedal-triggering text. + void ConvertInSuggestionPedalMatches(AutocompleteProviderClient* client); + // Sets |has_tab_match| in matches whose URL matches an open tab's URL. // Also, fixes up the description if not using another UI element to // annotate (e.g. tab switch button). |input| can be null; if provided,
diff --git a/components/omnibox/browser/mock_autocomplete_provider_client.cc b/components/omnibox/browser/mock_autocomplete_provider_client.cc index 3ea1bb7..4b4f390 100644 --- a/components/omnibox/browser/mock_autocomplete_provider_client.cc +++ b/components/omnibox/browser/mock_autocomplete_provider_client.cc
@@ -16,6 +16,7 @@ /*identity_manager=*/nullptr, GetURLLoaderFactory()); document_suggestions_service_ = std::make_unique<DocumentSuggestionsService>( /*identity_manager=*/nullptr, GetURLLoaderFactory()); + pedal_provider_ = std::make_unique<OmniboxPedalProvider>(); } MockAutocompleteProviderClient::~MockAutocompleteProviderClient() {
diff --git a/components/omnibox/browser/mock_autocomplete_provider_client.h b/components/omnibox/browser/mock_autocomplete_provider_client.h index 4d13a42..0cc0d0f8 100644 --- a/components/omnibox/browser/mock_autocomplete_provider_client.h +++ b/components/omnibox/browser/mock_autocomplete_provider_client.h
@@ -15,6 +15,7 @@ #include "components/omnibox/browser/autocomplete_scheme_classifier.h" #include "components/omnibox/browser/contextual_suggestions_service.h" #include "components/omnibox/browser/document_suggestions_service.h" +#include "components/omnibox/browser/omnibox_pedal_provider.h" #include "components/search_engines/template_url_service.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -60,6 +61,9 @@ bool create_if_necessary) const override { return document_suggestions_service_.get(); } + OmniboxPedalProvider* GetPedalProvider() const override { + return pedal_provider_.get(); + } // Can't mock scoped_refptr :\. scoped_refptr<ShortcutsBackend> GetShortcutsBackend() override { @@ -116,6 +120,7 @@ std::unique_ptr<ContextualSuggestionsService> contextual_suggestions_service_; std::unique_ptr<DocumentSuggestionsService> document_suggestions_service_; + std::unique_ptr<OmniboxPedalProvider> pedal_provider_; std::unique_ptr<TemplateURLService> template_url_service_; DISALLOW_COPY_AND_ASSIGN(MockAutocompleteProviderClient);
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc index 4c9881a..6b62d0fb 100644 --- a/components/omnibox/browser/omnibox_edit_model.cc +++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -32,6 +32,7 @@ #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/omnibox_log.h" #include "components/omnibox/browser/omnibox_navigation_observer.h" +#include "components/omnibox/browser/omnibox_pedal.h" #include "components/omnibox/browser/omnibox_popup_model.h" #include "components/omnibox/browser/omnibox_popup_view.h" #include "components/omnibox/browser/omnibox_view.h" @@ -635,6 +636,20 @@ autocomplete_controller()->UpdateMatchDestinationURLWithQueryFormulationTime( elapsed_time_since_user_first_modified_omnibox, &match); + // TODO(orinj): This is being used to distinguish between button + // press and other (keyboard/click) acceptance of suggestion but + // if in-suggestion side button Pedals are liked/kept by UX & PM then + // the meaning should be clarified. Instead of relying on SWITCH_TO_TAB, + // it may make sense to add a new disposition and change/move this code. + const bool button_pressed = + disposition == WindowOpenDisposition::SWITCH_TO_TAB; + if (match.pedal && match.pedal->ShouldExecute(button_pressed)) { + OmniboxPedal::ExecutionContext context(*client_, *controller_, + match_selection_timestamp); + match.pedal->Execute(context); + return; + } + base::string16 input_text(pasted_text); if (input_text.empty()) input_text = user_input_in_progress_ ? user_text_ : url_for_editing_; @@ -768,6 +783,7 @@ base::RecordAction( base::UserMetricsAction("OmniboxDestinationURLIsSearchOnDSP")); } + if (match.destination_url.is_valid()) { // This calls RevertAll again. base::AutoReset<bool> tmp(&in_revert_, true); @@ -1394,10 +1410,14 @@ (!popup_model() || !popup_model()->has_selected_match())) *alternate_nav_url = result().alternate_nav_url(); } else { + base::string16 text_for_match_generation = + (user_input_in_progress() || GetQueryInOmniboxSearchTerms(nullptr)) + ? view_->GetText() + : url_for_editing_; + client_->GetAutocompleteClassifier()->Classify( - MaybePrependKeyword(user_input_in_progress_ ? view_->GetText() - : url_for_editing_), - is_keyword_selected(), true, ClassifyPage(), match, alternate_nav_url); + MaybePrependKeyword(text_for_match_generation), is_keyword_selected(), + true, ClassifyPage(), match, alternate_nav_url); } }
diff --git a/components/omnibox/browser/omnibox_edit_model_unittest.cc b/components/omnibox/browser/omnibox_edit_model_unittest.cc index 3607bd3..fd0dcfc2 100644 --- a/components/omnibox/browser/omnibox_edit_model_unittest.cc +++ b/components/omnibox/browser/omnibox_edit_model_unittest.cc
@@ -141,7 +141,7 @@ AutocompleteMatch match; match.type = AutocompleteMatchType::NAVSUGGEST; match.destination_url = GURL(input[i].match_destination_url); - model()->SetCurrentMatch(match); + model()->SetCurrentMatchForTest(match); base::string16 result = base::ASCIIToUTF16(input[i].input); GURL url; @@ -254,15 +254,32 @@ client->alternate_nav_match().fill_into_edit)); } -TEST_F(OmniboxEditModelTest, GenerateMatchesFromFullFormattedUrl) { +TEST_F(OmniboxEditModelTest, CurrentMatch) { toolbar_model()->set_formatted_full_url( base::ASCIIToUTF16("http://localhost/")); toolbar_model()->set_url_for_display(base::ASCIIToUTF16("localhost")); model()->ResetDisplayTexts(); - // Bypass the test class's mock method to test the real behavior. - AutocompleteMatch match = model()->OmniboxEditModel::CurrentMatch(nullptr); - EXPECT_EQ(AutocompleteMatchType::URL_WHAT_YOU_TYPED, match.type); + // Tests that we use the formatted full URL instead of the elided URL to + // generate matches. + { + AutocompleteMatch match = model()->CurrentMatch(nullptr); + EXPECT_EQ(AutocompleteMatchType::URL_WHAT_YOU_TYPED, match.type); + EXPECT_TRUE(model()->CurrentTextIsURL()); + } + + // Tests that when there is a Query in Omnibox, generate matches from the + // query, instead of the full formatted URL. + TestOmniboxClient* client = + static_cast<TestOmniboxClient*>(model()->client()); + client->SetFakeSearchTermsForQueryInOmnibox(base::ASCIIToUTF16("foobar")); + model()->ResetDisplayTexts(); + + { + AutocompleteMatch match = model()->CurrentMatch(nullptr); + EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, match.type); + EXPECT_FALSE(model()->CurrentTextIsURL()); + } } TEST_F(OmniboxEditModelTest, DisplayText) {
diff --git a/components/omnibox/browser/omnibox_metrics_provider.cc b/components/omnibox/browser/omnibox_metrics_provider.cc index de326d20..4a5447a 100644 --- a/components/omnibox/browser/omnibox_metrics_provider.cc +++ b/components/omnibox/browser/omnibox_metrics_provider.cc
@@ -66,6 +66,10 @@ return OmniboxEventProto::Suggestion::CLIPBOARD; case AutocompleteMatchType::DOCUMENT_SUGGESTION: return OmniboxEventProto::Suggestion::DOCUMENT; + case AutocompleteMatchType::PEDAL: + // TODO(orinj): Add a new OmniboxEventProto type for Pedals. + // return OmniboxEventProto::Suggestion::PEDAL; + return OmniboxEventProto::Suggestion::NAVSUGGEST; case AutocompleteMatchType::VOICE_SUGGEST: // VOICE_SUGGEST matches are only used in Java and are not logged, // so we should never reach this case.
diff --git a/components/omnibox/browser/omnibox_pedal.cc b/components/omnibox/browser/omnibox_pedal.cc index 860c7fa..97848d85 100644 --- a/components/omnibox/browser/omnibox_pedal.cc +++ b/components/omnibox/browser/omnibox_pedal.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "components/omnibox/browser/omnibox_pedal.h" + #include "base/strings/utf_string_conversions.h" #include "components/omnibox/browser/omnibox_client.h" #include "components/omnibox/browser/omnibox_edit_controller.h" @@ -26,6 +27,14 @@ return strings_; } +bool OmniboxPedal::IsNavigation() const { + return !url_.is_empty(); +} + +const GURL& OmniboxPedal::GetNavigationUrl() const { + return url_; +} + bool OmniboxPedal::ShouldExecute(bool button_pressed) const { const auto mode = OmniboxFieldTrial::GetPedalSuggestionMode(); return (mode == OmniboxFieldTrial::PedalSuggestionMode::DEDICATED) || @@ -38,16 +47,20 @@ OmniboxFieldTrial::PedalSuggestionMode::IN_SUGGESTION; } +void OmniboxPedal::Execute(OmniboxPedal::ExecutionContext& context) const { + DCHECK(IsNavigation()); + OpenURL(context, url_); +} + bool OmniboxPedal::IsTriggerMatch(const base::string16& match_text) const { return triggers_.find(match_text) != triggers_.end(); } void OmniboxPedal::OpenURL(OmniboxPedal::ExecutionContext& context, const GURL& url) const { - // TODO(orinj): This will use AutocompleteMatchType::PEDAL context.controller_.OnAutocompleteAccept( url, WindowOpenDisposition::CURRENT_TAB, ui::PAGE_TRANSITION_GENERATED, - AutocompleteMatchType::NAVSUGGEST, context.match_selection_timestamp_); + AutocompleteMatchType::PEDAL, context.match_selection_timestamp_); } // ============================================================================= @@ -57,6 +70,7 @@ IDS_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA_HINT, IDS_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA_HINT_SHORT, IDS_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA_SUGGESTION_CONTENTS)) { + url_ = GURL("chrome://settings/clearBrowserData"); // TODO(orinj): Move all trigger strings to files (maybe even per language). const auto triggers = { "how to clear browsing data on chrome", @@ -85,7 +99,110 @@ } } -void OmniboxPedalClearBrowsingData::Execute( - OmniboxPedal::ExecutionContext& context) const { - OpenURL(context, GURL("chrome://settings/clearBrowserData")); +// ============================================================================= + +OmniboxPedalChangeSearchEngine::OmniboxPedalChangeSearchEngine() + : OmniboxPedal(OmniboxPedal::LabelStrings( + IDS_OMNIBOX_PEDAL_CHANGE_SEARCH_ENGINE_HINT, + IDS_OMNIBOX_PEDAL_CHANGE_SEARCH_ENGINE_HINT_SHORT, + IDS_OMNIBOX_PEDAL_CHANGE_SEARCH_ENGINE_SUGGESTION_CONTENTS)) { + url_ = GURL("chrome://settings/searchEngines"); + const auto triggers = { + "how to change search engine", + "how to change default search engine", + "how to change default search engine in chrome", + "how to change search engine on chrome", + "how to set google as default search engine on chrome", + "how to set google as default search engine in chrome", + "how to make google default search engine", + "how to change default search engine in google chrome", + "change search engine", + "change google search engine", + "change chrome searh engine", + "change default search engine in chrome", + "change search engine chrome", + "change default search chrome", + "change search chrome", + "switch chrome search engine", + "switch search engine", + }; + + for (const auto* trigger : triggers) { + triggers_.insert(base::ASCIIToUTF16(trigger)); + } +} + +// ============================================================================= + +OmniboxPedalManagePasswords::OmniboxPedalManagePasswords() + : OmniboxPedal(OmniboxPedal::LabelStrings( + IDS_OMNIBOX_PEDAL_MANAGE_PASSWORDS_HINT, + IDS_OMNIBOX_PEDAL_MANAGE_PASSWORDS_HINT_SHORT, + IDS_OMNIBOX_PEDAL_MANAGE_PASSWORDS_SUGGESTION_CONTENTS)) { + url_ = GURL("chrome://settings/passwords"); + const auto triggers = { + "passwords", + "find my passwords", + "save passwords in chrome", + "view saved passwords", + "delete passwords", + "find saved passwords", + "where does chrome store passwords", + "how to see passwords in chrome", + }; + + for (const auto* trigger : triggers) { + triggers_.insert(base::ASCIIToUTF16(trigger)); + } +} + +// ============================================================================= + +OmniboxPedalChangeHomePage::OmniboxPedalChangeHomePage() + : OmniboxPedal(OmniboxPedal::LabelStrings( + IDS_OMNIBOX_PEDAL_CHANGE_HOME_PAGE_HINT, + IDS_OMNIBOX_PEDAL_CHANGE_HOME_PAGE_HINT_SHORT, + IDS_OMNIBOX_PEDAL_CHANGE_HOME_PAGE_SUGGESTION_CONTENTS)) { + // TODO(orinj): Use better scoping for existing setting, or link to a new UI. + url_ = GURL("chrome://settings/?search=show+home+button"); + const auto triggers = { + "how to change home page", + "how to change your home page", + "how do i change my home page", + "change home page google", + "home page chrome", + "change home chrome", + "change chrome home page", + "how to change home page on chrome", + "how to change home page in chrome", + "change chrome home", + }; + + for (const auto* trigger : triggers) { + triggers_.insert(base::ASCIIToUTF16(trigger)); + } +} + +// ============================================================================= + +OmniboxPedalUpdateCreditCard::OmniboxPedalUpdateCreditCard() + : OmniboxPedal(OmniboxPedal::LabelStrings( + IDS_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_HINT, + IDS_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_HINT_SHORT, + IDS_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_SUGGESTION_CONTENTS)) { + url_ = GURL("chrome://settings/autofill"); + const auto triggers = { + "how to save credit card info on chrome", + "how to remove credit card from google chrome", + "remove google chrome credit cards", + "access google chrome credit cards", + "google chrome credit cards", + "chrome credit cards", + "get to chrome credit cards", + "chrome credit saved", + }; + + for (const auto* trigger : triggers) { + triggers_.insert(base::ASCIIToUTF16(trigger)); + } }
diff --git a/components/omnibox/browser/omnibox_pedal.h b/components/omnibox/browser/omnibox_pedal.h index d5842ff..af0e590 100644 --- a/components/omnibox/browser/omnibox_pedal.h +++ b/components/omnibox/browser/omnibox_pedal.h
@@ -58,6 +58,12 @@ // Provides read access to labels associated with this Pedal. const LabelStrings& GetLabelStrings() const; + // Returns true if this is purely a navigation Pedal with URL. + bool IsNavigation() const; + + // For navigation Pedals, returns the destination URL. + const GURL& GetNavigationUrl() const; + // These Should* methods can likely be eliminated when Pedal // suggestion mode is firmly established. @@ -70,8 +76,9 @@ // button; this method returns true if this Pedal presents a button. virtual bool ShouldPresentButton() const; - // Takes the action associated with this Pedal. - virtual void Execute(ExecutionContext& context) const = 0; + // Takes the action associated with this Pedal. Non-navigation + // Pedals must override the default, but Navigation Pedals don't need to. + virtual void Execute(ExecutionContext& context) const; // Returns true if the preprocessed match suggestion text triggers // presentation of this Pedal. This is not intended for general use, @@ -84,12 +91,35 @@ std::unordered_set<base::string16> triggers_; LabelStrings strings_; + + // For navigation Pedals, this holds the destination URL; for action Pedals, + // this remains empty. + GURL url_; }; class OmniboxPedalClearBrowsingData : public OmniboxPedal { public: OmniboxPedalClearBrowsingData(); - void Execute(ExecutionContext& context) const override; +}; + +class OmniboxPedalChangeSearchEngine : public OmniboxPedal { + public: + OmniboxPedalChangeSearchEngine(); +}; + +class OmniboxPedalManagePasswords : public OmniboxPedal { + public: + OmniboxPedalManagePasswords(); +}; + +class OmniboxPedalChangeHomePage : public OmniboxPedal { + public: + OmniboxPedalChangeHomePage(); +}; + +class OmniboxPedalUpdateCreditCard : public OmniboxPedal { + public: + OmniboxPedalUpdateCreditCard(); }; #endif // COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_PEDAL_H_
diff --git a/components/omnibox/browser/omnibox_pedal_provider.cc b/components/omnibox/browser/omnibox_pedal_provider.cc index edda980d..916855a1 100644 --- a/components/omnibox/browser/omnibox_pedal_provider.cc +++ b/components/omnibox/browser/omnibox_pedal_provider.cc
@@ -31,4 +31,8 @@ void OmniboxPedalProvider::RegisterPedals() { Add(new OmniboxPedalClearBrowsingData()); + Add(new OmniboxPedalChangeSearchEngine()); + Add(new OmniboxPedalManagePasswords()); + Add(new OmniboxPedalChangeHomePage()); + Add(new OmniboxPedalUpdateCreditCard()); }
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc index a84ce9b..bd35b43a1 100644 --- a/components/omnibox/browser/omnibox_popup_model.cc +++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -199,7 +199,9 @@ } if (state == TAB_SWITCH) { - DCHECK(match.has_tab_match); + // TODO(orinj): If in-suggestion Pedals are kept, refactor a bit + // so that button presence doesn't always assume tab switching use case. + DCHECK(match.has_tab_match || match.pedal); old_focused_url_ = current_destination; }
diff --git a/components/omnibox/browser/omnibox_view_unittest.cc b/components/omnibox/browser/omnibox_view_unittest.cc index f251de4..cc24f10 100644 --- a/components/omnibox/browser/omnibox_view_unittest.cc +++ b/components/omnibox/browser/omnibox_view_unittest.cc
@@ -164,7 +164,7 @@ AutocompleteMatch match; match.destination_url = kUrl; - model()->SetCurrentMatch(match); + model()->SetCurrentMatchForTest(match); bookmark_model()->AddURL(bookmark_model()->bookmark_bar_node(), 0, base::ASCIIToUTF16("a bookmark"), kUrl); @@ -190,7 +190,7 @@ AutocompleteMatch match; match.type = AutocompleteMatchType::URL_WHAT_YOU_TYPED; match.destination_url = kUrl; - model()->SetCurrentMatch(match); + model()->SetCurrentMatchForTest(match); view()->GetIcon(gfx::kFaviconSize, gfx::kPlaceholderColor, base::DoNothing());
diff --git a/components/omnibox/browser/test_omnibox_edit_model.cc b/components/omnibox/browser/test_omnibox_edit_model.cc index a754c8bc..f228a58 100644 --- a/components/omnibox/browser/test_omnibox_edit_model.cc +++ b/components/omnibox/browser/test_omnibox_edit_model.cc
@@ -12,18 +12,25 @@ : OmniboxEditModel(view, controller, std::make_unique<TestOmniboxClient>()), popup_is_open_(false) {} +TestOmniboxEditModel::~TestOmniboxEditModel() {} + bool TestOmniboxEditModel::PopupIsOpen() const { return popup_is_open_; } -AutocompleteMatch TestOmniboxEditModel::CurrentMatch(GURL*) const { - return current_match_; +AutocompleteMatch TestOmniboxEditModel::CurrentMatch( + GURL* alternate_nav_url) const { + if (override_current_match_) + return *override_current_match_; + + return OmniboxEditModel::CurrentMatch(alternate_nav_url); } void TestOmniboxEditModel::SetPopupIsOpen(bool open) { popup_is_open_ = open; } -void TestOmniboxEditModel::SetCurrentMatch(const AutocompleteMatch& match) { - current_match_ = match; +void TestOmniboxEditModel::SetCurrentMatchForTest( + const AutocompleteMatch& match) { + override_current_match_ = std::make_unique<AutocompleteMatch>(match); }
diff --git a/components/omnibox/browser/test_omnibox_edit_model.h b/components/omnibox/browser/test_omnibox_edit_model.h index 98efbcc..ed252c9 100644 --- a/components/omnibox/browser/test_omnibox_edit_model.h +++ b/components/omnibox/browser/test_omnibox_edit_model.h
@@ -5,23 +5,26 @@ #ifndef COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_MODEL_H_ #define COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_MODEL_H_ +#include <memory> + #include "components/omnibox/browser/omnibox_edit_model.h" class TestOmniboxEditModel : public OmniboxEditModel { public: TestOmniboxEditModel(OmniboxView* view, OmniboxEditController* controller); + ~TestOmniboxEditModel() override; // OmniboxEditModel: bool PopupIsOpen() const override; - AutocompleteMatch CurrentMatch(GURL*) const override; + AutocompleteMatch CurrentMatch(GURL* alternate_nav_url) const override; void SetPopupIsOpen(bool open); - void SetCurrentMatch(const AutocompleteMatch& match); + void SetCurrentMatchForTest(const AutocompleteMatch& match); private: bool popup_is_open_; - AutocompleteMatch current_match_; + std::unique_ptr<AutocompleteMatch> override_current_match_; DISALLOW_COPY_AND_ASSIGN(TestOmniboxEditModel); };
diff --git a/components/omnibox_strings.grdp b/components/omnibox_strings.grdp index ced57c39..50c6ac4b 100644 --- a/components/omnibox_strings.grdp +++ b/components/omnibox_strings.grdp
@@ -85,6 +85,46 @@ Clear Chrome's browsing history data </message> + <message name="IDS_OMNIBOX_PEDAL_CHANGE_SEARCH_ENGINE_HINT" desc="The button text contents to suggest pedal action, change search engine."> + Change Search Engine + </message> + <message name="IDS_OMNIBOX_PEDAL_CHANGE_SEARCH_ENGINE_HINT_SHORT" desc="The short one-word button text contents to suggest pedal action, change search engine."> + Change + </message> + <message name="IDS_OMNIBOX_PEDAL_CHANGE_SEARCH_ENGINE_SUGGESTION_CONTENTS" desc="The suggestion content text to suggest pedal action, change search engine."> + Change Search Engine settings in Chrome + </message> + + <message name="IDS_OMNIBOX_PEDAL_MANAGE_PASSWORDS_HINT" desc="The button text contents to suggest pedal action, manage passwords."> + Manage Passwords + </message> + <message name="IDS_OMNIBOX_PEDAL_MANAGE_PASSWORDS_HINT_SHORT" desc="The short one-word button text contents to suggest pedal action, change language."> + Manage + </message> + <message name="IDS_OMNIBOX_PEDAL_MANAGE_PASSWORDS_SUGGESTION_CONTENTS" desc="The suggestion content text to suggest pedal action, change language."> + Manage passwords in Chrome settings + </message> + + <message name="IDS_OMNIBOX_PEDAL_CHANGE_HOME_PAGE_HINT" desc="The button text contents to suggest pedal action, change home page."> + Change Home Page + </message> + <message name="IDS_OMNIBOX_PEDAL_CHANGE_HOME_PAGE_HINT_SHORT" desc="The short one-word button text contents to suggest pedal action, change home page."> + Change + </message> + <message name="IDS_OMNIBOX_PEDAL_CHANGE_HOME_PAGE_SUGGESTION_CONTENTS" desc="The suggestion content text to suggest pedal action, change home page."> + Change home page in Chrome settings + </message> + + <message name="IDS_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_HINT" desc="The button text contents to suggest pedal action, update credit card."> + Update Credit Card + </message> + <message name="IDS_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_HINT_SHORT" desc="The short one-word button text contents to suggest pedal action, update credit card."> + Update + </message> + <message name="IDS_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_SUGGESTION_CONTENTS" desc="The suggestion content text to suggest pedal action, update credit card."> + Update credit card autofill info in Chrome settings + </message> + <!-- Accessibility labels for autocomplete match types. These are parameterized on the text being completed into the omnibox. -->
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 8571f957..e9f2281 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -10473,13 +10473,13 @@ 'desc': '''Enables <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>'s restricted log in feature in G Suite and prevents users from changing this setting. If you define this setting, the user will only be able to access Google - Apps using accounts from the specified domains (note that this does not - work for gmail.com/googlemail.com). + Apps using accounts from the specified domains (note that to allow + gmail.com/googlemail.com accounts, you should add "consumer_accounts" + (without quotes) to the list of domains). - This setting will NOT prevent the user from loging in on a managed device - that requires Google authentication. The user will still be allowed to - sign in to accounts from other domains, but they will receive an error - when trying to use G Suite with those accounts. + This setting will prevent the user from logging in, and adding a Secondary + Account, on a managed device that requires Google authentication, if that + account does not belong to the aforementioned list of allowed domains. If you leave this setting empty/not-configured, the user will be able to access G Suite with any account.
diff --git a/components/search/BUILD.gn b/components/search/BUILD.gn index b3896ba..d6d3db31 100644 --- a/components/search/BUILD.gn +++ b/components/search/BUILD.gn
@@ -14,6 +14,19 @@ "//components/search_engines", "//url", ] + + if (!is_ios && !is_android) { + sources += [ + "url_validity_checker.h", + "url_validity_checker_impl.cc", + "url_validity_checker_impl.h", + ] + + deps += [ + "//net", + "//services/network/public/cpp", + ] + } } source_set("unit_tests") { @@ -28,4 +41,15 @@ "//components/variations", "//testing/gtest", ] + + if (!is_ios && !is_android) { + sources += [ "url_validity_checker_impl_unittest.cc" ] + + deps += [ + "//net", + "//net:test_support", + "//services/network:test_support", + "//testing/gmock", + ] + } }
diff --git a/components/search/DEPS b/components/search/DEPS index d9bc813..8402eab 100644 --- a/components/search/DEPS +++ b/components/search/DEPS
@@ -2,4 +2,7 @@ "+components/google/core", "+components/search_engines", "+components/variations", + "+net", + "+services/network/public/cpp", + "+services/network/test", ]
diff --git a/components/search/url_validity_checker.h b/components/search/url_validity_checker.h new file mode 100644 index 0000000..8ac60fa --- /dev/null +++ b/components/search/url_validity_checker.h
@@ -0,0 +1,31 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SEARCH_URL_VALIDITY_CHECKER_H_ +#define COMPONENTS_SEARCH_URL_VALIDITY_CHECKER_H_ + +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "url/gurl.h" + +// A standalone service that validates if the provided URL is able to resolve to +// a valid page. +class UrlValidityChecker { + public: + // The callback invoked when the request completes. Returns true if the + // response was |valid| and the request |duration|. + using UrlValidityCheckerCallback = + base::OnceCallback<void(bool valid, const base::TimeDelta& duration)>; + + virtual ~UrlValidityChecker() = default; + + // Creates a HEAD request to check if |url| resolves to an existing page. + // Returns true if the URL resolves and the request duration. Redirects (3xx) + // and 2xx response codes are considered as resolving. + virtual void DoesUrlResolve( + const GURL& url, + net::NetworkTrafficAnnotationTag traffic_annotation, + UrlValidityCheckerCallback callback) = 0; +}; + +#endif // COMPONENTS_SEARCH_URL_VALIDITY_CHECKER_H_
diff --git a/components/search/url_validity_checker_impl.cc b/components/search/url_validity_checker_impl.cc new file mode 100644 index 0000000..accddbfa --- /dev/null +++ b/components/search/url_validity_checker_impl.cc
@@ -0,0 +1,86 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/search/url_validity_checker_impl.h" + +#include "base/bind.h" +#include "base/time/time.h" +#include "base/timer/timer.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_status_code.h" + +// Stores the pending request and associated metadata. Deleted once the request +// finishes. +struct UrlValidityCheckerImpl::PendingRequest { + PendingRequest() = default; + + GURL url; + base::TimeTicks time_created; + UrlValidityCheckerCallback callback; + std::unique_ptr<network::SimpleURLLoader> loader; + + DISALLOW_COPY_AND_ASSIGN(PendingRequest); +}; + +UrlValidityCheckerImpl::UrlValidityCheckerImpl( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) + : url_loader_factory_(url_loader_factory) {} + +UrlValidityCheckerImpl::~UrlValidityCheckerImpl() = default; + +void UrlValidityCheckerImpl::DoesUrlResolve( + const GURL& url, + net::NetworkTrafficAnnotationTag traffic_annotation, + UrlValidityCheckerCallback callback) { + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->url = url; + resource_request->method = "HEAD"; + resource_request->allow_credentials = false; + + auto request_iter = pending_requests_.emplace(pending_requests_.begin()); + request_iter->url = url; + request_iter->time_created = NowTicks(); + request_iter->callback = std::move(callback); + request_iter->loader = network::SimpleURLLoader::Create( + std::move(resource_request), traffic_annotation); + // Don't follow redirects to prevent leaking URL data to HTTP sites. + request_iter->loader->SetOnRedirectCallback( + base::BindRepeating(&UrlValidityCheckerImpl::OnSimpleLoaderRedirect, + weak_ptr_factory_.GetWeakPtr(), request_iter)); + request_iter->loader->DownloadToString( + url_loader_factory_.get(), + base::BindOnce(&UrlValidityCheckerImpl::OnSimpleLoaderComplete, + weak_ptr_factory_.GetWeakPtr(), request_iter), + /*max_body_size=*/1); +} + +void UrlValidityCheckerImpl::OnSimpleLoaderRedirect( + std::list<PendingRequest>::iterator request_iter, + const net::RedirectInfo& redirect_info, + const network::ResourceResponseHead& response_head, + std::vector<std::string>* to_be_removed_headers) { + // Assume the URL is valid if a redirect is returned. + OnSimpleLoaderHandler(request_iter, true); +} + +void UrlValidityCheckerImpl::OnSimpleLoaderComplete( + std::list<PendingRequest>::iterator request_iter, + std::unique_ptr<std::string> response_body) { + // |response_body| is null for non-2xx responses. + OnSimpleLoaderHandler(request_iter, response_body.get() != nullptr); +} + +void UrlValidityCheckerImpl::OnSimpleLoaderHandler( + std::list<PendingRequest>::iterator request_iter, + bool valid) { + base::TimeDelta elapsed_time = NowTicks() - request_iter->time_created; + std::move(request_iter->callback).Run(valid, elapsed_time); + pending_requests_.erase(request_iter); +} + +base::TimeTicks UrlValidityCheckerImpl::NowTicks() const { + if (!time_ticks_for_testing_.is_null()) + return time_ticks_for_testing_; + return base::TimeTicks::Now(); +}
diff --git a/components/search/url_validity_checker_impl.h b/components/search/url_validity_checker_impl.h new file mode 100644 index 0000000..fea4b02 --- /dev/null +++ b/components/search/url_validity_checker_impl.h
@@ -0,0 +1,73 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SEARCH_URL_VALIDITY_CHECKER_IMPL_H_ +#define COMPONENTS_SEARCH_URL_VALIDITY_CHECKER_IMPL_H_ + +#include <list> +#include <vector> + +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "build/build_config.h" +#include "components/search/url_validity_checker.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" + +namespace net { +struct RedirectInfo; +} // namespace net + +namespace network { +struct ResourceResponseHead; +class SharedURLLoaderFactory; +} // namespace network + +class UrlValidityCheckerImpl : public UrlValidityChecker { + public: + explicit UrlValidityCheckerImpl( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); + ~UrlValidityCheckerImpl() override; + + void DoesUrlResolve(const GURL& url, + net::NetworkTrafficAnnotationTag traffic_annotation, + UrlValidityCheckerCallback callback) override; + + // Used for testing. + void SetTimeTicksForTesting(const base::TimeTicks& time_ticks) { + time_ticks_for_testing_ = time_ticks; + } + + private: + struct PendingRequest; + + void OnSimpleLoaderRedirect( + std::list<PendingRequest>::iterator request_iter, + const net::RedirectInfo& redirect_info, + const network::ResourceResponseHead& response_head, + std::vector<std::string>* to_be_removed_headers); + void OnSimpleLoaderComplete(std::list<PendingRequest>::iterator request_iter, + std::unique_ptr<std::string> response_body); + // Called when the request from |DoesUrlResolve| finishes. Invokes the + // associated callback with the request status and duration. + void OnSimpleLoaderHandler(std::list<PendingRequest>::iterator request_iter, + bool valid); + + // Returns base::TimeTicks::Now() or the test TimeTicks if not null. + base::TimeTicks NowTicks() const; + + // Stores any ongoing network requests. Once a request is completed, it is + // deleted from the list. + std::list<PendingRequest> pending_requests_; + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + + // Test time ticks used for testing. + base::TimeTicks time_ticks_for_testing_; + + base::WeakPtrFactory<UrlValidityCheckerImpl> weak_ptr_factory_{this}; + + DISALLOW_COPY_AND_ASSIGN(UrlValidityCheckerImpl); +}; + +#endif // COMPONENTS_SEARCH_URL_VALIDITY_CHECKER_IMPL_H_
diff --git a/components/search/url_validity_checker_impl_unittest.cc b/components/search/url_validity_checker_impl_unittest.cc new file mode 100644 index 0000000..4c154bf --- /dev/null +++ b/components/search/url_validity_checker_impl_unittest.cc
@@ -0,0 +1,146 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/search/url_validity_checker_impl.h" + +#include "base/files/file_util.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/test/bind_test_util.h" +#include "base/test/mock_callback.h" +#include "base/test/scoped_task_environment.h" +#include "base/test/simple_test_tick_clock.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +using ::testing::_; + +class UrlValidityCheckerImplTest : public testing::Test { + protected: + UrlValidityCheckerImplTest() + : test_shared_loader_factory_( + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_)), + url_checker_(test_shared_loader_factory_) { + // Start |clock_| at non-zero. + clock_.Advance(base::TimeDelta::FromSeconds(1)); + } + + ~UrlValidityCheckerImplTest() override {} + + void SetUp() override { + test_shared_loader_factory_ = + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + url_loader_factory()); + url_checker()->SetTimeTicksForTesting(clock_.NowTicks()); + } + + UrlValidityCheckerImpl* url_checker() { return &url_checker_; } + + network::TestURLLoaderFactory* url_loader_factory() { + return &test_url_loader_factory_; + } + + void AdvanceClock(const base::TimeDelta& delta) { + clock_.Advance(delta); + url_checker()->SetTimeTicksForTesting(clock_.NowTicks()); + } + + base::test::ScopedTaskEnvironment scoped_task_environment_; + + private: + network::TestURLLoaderFactory test_url_loader_factory_; + scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; + + base::SimpleTestTickClock clock_; + UrlValidityCheckerImpl url_checker_; + + DISALLOW_COPY_AND_ASSIGN(UrlValidityCheckerImplTest); +}; + +TEST_F(UrlValidityCheckerImplTest, DoesUrlResolve_OnSuccess) { + const GURL kUrl("https://www.foo.com"); + const int kTimeAdvance = 10; + base::TimeDelta expected_duration = + base::TimeDelta::FromSeconds(kTimeAdvance); + + network::ResourceResponseHead response; + response.headers = new net::HttpResponseHeaders( + "HTTP/1.1 200 OK\nContent-type: text/html\n\n"); + url_loader_factory()->SetInterceptor( + base::BindLambdaForTesting([&](const network::ResourceRequest& request) { + AdvanceClock(expected_duration); + url_loader_factory()->AddResponse( + request.url, response, std::string(), + network::URLLoaderCompletionStatus(net::OK)); + })); + base::MockCallback<UrlValidityChecker::UrlValidityCheckerCallback> + callback_ok; + EXPECT_CALL(callback_ok, Run(true, expected_duration)); + + url_checker()->DoesUrlResolve(kUrl, TRAFFIC_ANNOTATION_FOR_TESTS, + callback_ok.Get()); + scoped_task_environment_.RunUntilIdle(); + + response.headers = + new net::HttpResponseHeaders("HTTP/1.1 204 No Content\r\n\r\n"); + base::MockCallback<UrlValidityChecker::UrlValidityCheckerCallback> + callback_no_content; + EXPECT_CALL(callback_no_content, Run(true, expected_duration)); + + url_checker()->DoesUrlResolve(kUrl, TRAFFIC_ANNOTATION_FOR_TESTS, + callback_no_content.Get()); + scoped_task_environment_.RunUntilIdle(); +} + +TEST_F(UrlValidityCheckerImplTest, DoesUrlResolve_OnFailure) { + const GURL kUrl("https://www.foo.com"); + const int kTimeAdvance = 20; + base::TimeDelta expected_duration = + base::TimeDelta::FromSeconds(kTimeAdvance); + + url_loader_factory()->SetInterceptor( + base::BindLambdaForTesting([&](const network::ResourceRequest& request) { + AdvanceClock(expected_duration); + url_loader_factory()->AddResponse( + request.url, network::ResourceResponseHead(), std::string(), + network::URLLoaderCompletionStatus(net::ERR_FAILED)); + })); + base::MockCallback<UrlValidityChecker::UrlValidityCheckerCallback> callback; + EXPECT_CALL(callback, Run(false, expected_duration)); + + url_checker()->DoesUrlResolve(kUrl, TRAFFIC_ANNOTATION_FOR_TESTS, + callback.Get()); + scoped_task_environment_.RunUntilIdle(); +} + +TEST_F(UrlValidityCheckerImplTest, DoesUrlResolve_OnRedirect) { + const GURL kUrl("https://www.foo.com"); + const GURL kRedirectUrl("https://www.foo2.com"); + const int kTimeAdvance = 30; + base::TimeDelta expected_duration = + base::TimeDelta::FromSeconds(kTimeAdvance); + + net::RedirectInfo redirect_info; + redirect_info.status_code = 301; + redirect_info.new_url = kRedirectUrl; + network::TestURLLoaderFactory::Redirects redirects{ + {redirect_info, network::ResourceResponseHead()}}; + url_loader_factory()->SetInterceptor( + base::BindLambdaForTesting([&](const network::ResourceRequest& request) { + AdvanceClock(expected_duration); + url_loader_factory()->AddResponse( + request.url, network::ResourceResponseHead(), std::string(), + network::URLLoaderCompletionStatus(), redirects); + })); + base::MockCallback<UrlValidityChecker::UrlValidityCheckerCallback> callback; + EXPECT_CALL(callback, Run(true, expected_duration)); + + url_checker()->DoesUrlResolve(kUrl, TRAFFIC_ANNOTATION_FOR_TESTS, + callback.Get()); + scoped_task_environment_.RunUntilIdle(); +}
diff --git a/components/viz/host/gpu_client.cc b/components/viz/host/gpu_client.cc index d526482..2dd5619f 100644 --- a/components/viz/host/gpu_client.cc +++ b/components/viz/host/gpu_client.cc
@@ -76,6 +76,10 @@ connection_error_handler_ = std::move(connection_error_handler); } +base::WeakPtr<GpuClient> GpuClient::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + void GpuClient::OnEstablishGpuChannel( mojo::ScopedMessagePipeHandle channel_handle, const gpu::GPUInfo& gpu_info,
diff --git a/components/viz/host/gpu_client.h b/components/viz/host/gpu_client.h index 53006ac..fdfcb9fd 100644 --- a/components/viz/host/gpu_client.h +++ b/components/viz/host/gpu_client.h
@@ -37,6 +37,8 @@ void SetConnectionErrorHandler( ConnectionErrorHandlerClosure connection_error_handler); + base::WeakPtr<GpuClient> GetWeakPtr(); + // ws::mojom::GpuMemoryBufferFactory overrides: void CreateGpuMemoryBuffer( gfx::GpuMemoryBufferId id,
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 6328c62..7750b5a3 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -2093,8 +2093,6 @@ "renderer_host/pepper/pepper_vpn_provider_message_filter_chromeos.h", "renderer_host/pepper/quota_reservation.cc", "renderer_host/pepper/quota_reservation.h", - "renderer_host/pepper/ssl_context_helper.cc", - "renderer_host/pepper/ssl_context_helper.h", "renderer_host/plugin_registry_impl.cc", "renderer_host/plugin_registry_impl.h", ]
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index 5635ed5..ec60dd6b 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -2243,6 +2243,7 @@ return @""; } else if (owner_->HasIntAttribute(ax::mojom::IntAttribute::kCheckedState) || [role isEqualToString:NSAccessibilityRadioButtonRole]) { + // On Mac, tabs are exposed as radio buttons, and are treated as checkable. int value; const auto checkedState = static_cast<ax::mojom::CheckedState>( owner_->GetIntAttribute(ax::mojom::IntAttribute::kCheckedState));
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index e324470..1ba2c301 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc
@@ -776,7 +776,7 @@ std::string protocol = info.alpn_negotiated_protocol; if (protocol.empty() || protocol == "unknown") { if (info.was_fetched_via_spdy) { - protocol = "spdy"; + protocol = "h2"; } else if (url.SchemeIsHTTPOrHTTPS()) { protocol = "http"; if (info.headers->GetHttpVersion() == net::HttpVersion(0, 9))
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc index 66f1270..96c9cd1 100644 --- a/content/browser/frame_host/render_widget_host_view_guest.cc +++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -338,6 +338,18 @@ return platform_view_->GetSelectedText(); } +base::string16 RenderWidgetHostViewGuest::GetSurroundingText() { + return platform_view_->GetSurroundingText(); +} + +gfx::Range RenderWidgetHostViewGuest::GetSelectedRange() { + return platform_view_->GetSelectedRange(); +} + +size_t RenderWidgetHostViewGuest::GetOffsetForSurroundingText() { + return platform_view_->GetOffsetForSurroundingText(); +} + void RenderWidgetHostViewGuest::SetNeedsBeginFrames(bool needs_begin_frames) { if (platform_view_) platform_view_->SetNeedsBeginFrames(needs_begin_frames);
diff --git a/content/browser/frame_host/render_widget_host_view_guest.h b/content/browser/frame_host/render_widget_host_view_guest.h index b3353f56..dae838f 100644 --- a/content/browser/frame_host/render_widget_host_view_guest.h +++ b/content/browser/frame_host/render_widget_host_view_guest.h
@@ -80,6 +80,9 @@ gfx::Rect GetBoundsInRootWindow() override; gfx::Size GetCompositorViewportPixelSize() const override; base::string16 GetSelectedText() override; + base::string16 GetSurroundingText() override; + gfx::Range GetSelectedRange() override; + size_t GetOffsetForSurroundingText() override; void SetNeedsBeginFrames(bool needs_begin_frames) override; TouchSelectionControllerClientManager* GetTouchSelectionControllerClientManager() override;
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index cb77aba..d38c982 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -826,7 +826,8 @@ // This is the |fallback_callback| passed to // NavigationLoaderInterceptor::MaybeCreateLoader. It allows an interceptor // to initially elect to handle a request, and later decide to fallback to - // the default behavior. This is needed for service worker network fallback. + // the default behavior. This is needed for service worker network fallback + // and signed exchange (SXG) fallback redirect. void FallbackToNonInterceptedRequest(bool reset_subresource_loader_params) { if (reset_subresource_loader_params) subresource_loader_params_.reset(); @@ -835,21 +836,35 @@ // Cancel state on ResourceDispatcherHostImpl so it doesn't complain about // reusing the request_id after redirects. Otherwise the following sequence // can happen: - // RDHI Start(request_id) -> Redirect -> SW interception -> SW fallback to - // network -> RDHI Start(request_id). + // case 1. RDHI Start(request_id) -> Redirect -> SW interception -> SW + // fallback to network -> RDHI Start(request_id). + // case 2. RDHI Start(request_id) -> SXG interception -> SXG fallback to + // network -> RDHI Start(request_id). if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) { DCHECK(ResourceDispatcherHostImpl::Get()); ResourceDispatcherHostImpl::Get()->CancelRequest( global_request_id_.child_id, global_request_id_.request_id); } - // |url_loader_| is using the factory for the interceptor that decided to - // fallback, so restart it with the non-interceptor factory. - DCHECK(url_loader_); uint32_t options = network::mojom::kURLLoadOptionNone; scoped_refptr<network::SharedURLLoaderFactory> factory = PrepareForNonInterceptedRequest(&options); - url_loader_->RestartWithFactory(std::move(factory), options); + if (url_loader_) { + // |url_loader_| is using the factory for the interceptor that decided to + // fallback, so restart it with the non-interceptor factory. + url_loader_->RestartWithFactory(std::move(factory), options); + } else { + // In SXG cases we don't have |url_loader_| because it was reset when the + // SXG interceptor intercepted the response in + // MaybeCreateLoaderForResponse. + DCHECK(response_loader_binding_); + response_loader_binding_.Close(); + url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart( + std::move(factory), CreateURLLoaderThrottles(), frame_tree_node_id_, + global_request_id_.request_id, options, resource_request_.get(), + this /* client */, kNavigationUrlLoaderTrafficAnnotation, + base::ThreadTaskRunnerHandle::Get()); + } } scoped_refptr<network::SharedURLLoaderFactory>
diff --git a/content/browser/media/media_internals.cc b/content/browser/media/media_internals.cc index 3553320c..7c6394853 100644 --- a/content/browser/media/media_internals.cc +++ b/content/browser/media/media_internals.cc
@@ -9,6 +9,7 @@ #include <tuple> #include <utility> +#include "base/containers/adapters.h" #include "base/macros.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" @@ -856,15 +857,19 @@ // We should go backwards through the stack so the top of the stack is // always shown first in the list. base::ListValue stack_data; - for (auto iter = stack.rbegin(); iter != stack.rend(); ++iter) { - int request_id = (*iter)->request_id; + for (const auto& session : base::Reversed(stack)) { + if (!session->request_id.has_value()) + continue; + + std::string id_string = session->request_id.value().ToString(); base::DictionaryValue media_session_data; - media_session_data.SetKey(kAudioFocusIdKey, base::Value(request_id)); + media_session_data.SetKey(kAudioFocusIdKey, base::Value(id_string)); stack_data.GetList().push_back(std::move(media_session_data)); audio_focus_debug_ptr_->GetDebugInfoForRequest( - request_id, base::BindOnce(&MediaInternals::DidGetAudioFocusDebugInfo, - base::Unretained(this), request_id)); + session->request_id.value(), + base::BindOnce(&MediaInternals::DidGetAudioFocusDebugInfo, + base::Unretained(this), id_string)); } audio_focus_data_.SetKey(kAudioFocusSessionsKey, std::move(stack_data)); @@ -874,7 +879,7 @@ } void MediaInternals::DidGetAudioFocusDebugInfo( - int id, + const std::string& id, media_session::mojom::MediaSessionDebugInfoPtr info) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -887,7 +892,7 @@ bool updated = false; for (auto& session : sessions_list->GetList()) { - if (session.FindKey(kAudioFocusIdKey)->GetInt() != id) + if (session.FindKey(kAudioFocusIdKey)->GetString() != id) continue; session.SetKey("name", base::Value(info->name));
diff --git a/content/browser/media/media_internals.h b/content/browser/media/media_internals.h index 3e42a724..0ad0fc2a 100644 --- a/content/browser/media/media_internals.h +++ b/content/browser/media/media_internals.h
@@ -133,7 +133,7 @@ // Called when we receive audio focus debug info to display for a single // audio focus request. void DidGetAudioFocusDebugInfo( - int id, + const std::string& id, media_session::mojom::MediaSessionDebugInfoPtr info); // Sends |update| to each registered UpdateCallback. Safe to call from any
diff --git a/content/browser/media/media_internals_unittest.cc b/content/browser/media/media_internals_unittest.cc index cd3159c..32a85ae 100644 --- a/content/browser/media/media_internals_unittest.cc +++ b/content/browser/media/media_internals_unittest.cc
@@ -28,6 +28,7 @@ #include "media/base/media_switches.h" #include "services/media_session/public/cpp/switches.h" #include "services/media_session/public/mojom/audio_focus.mojom.h" +#include "services/media_session/public/mojom/constants.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/size.h" @@ -36,6 +37,8 @@ const int kTestComponentID = 0; const char kTestDeviceID[] = "test-device-id"; +using media_session::mojom::AudioFocusRequestStatePtr; + // This class encapsulates a MediaInternals reference. It also has some useful // methods to receive a callback, deserialize its associated data and expect // integer/string values. @@ -327,7 +330,9 @@ browser_context_.reset(new TestBrowserContext()); run_loop_ = std::make_unique<base::RunLoop>(); - run_loop_ = std::make_unique<base::RunLoop>(); + content::ServiceManagerConnection::GetForProcess() + ->GetConnector() + ->BindInterface(media_session::mojom::kServiceName, &audio_focus_ptr_); content::MediaInternals::GetInstance()->AddUpdateCallback(update_cb_); } @@ -394,6 +399,20 @@ run_loop_->Run(); } + std::string GetRequestIdForTopFocusRequest() { + std::string result; + + audio_focus_ptr_->GetFocusRequests(base::BindOnce( + [](std::string* out, std::vector<AudioFocusRequestStatePtr> requests) { + DCHECK(!requests.empty()); + *out = requests.back()->request_id.value().ToString(); + }, + &result)); + + audio_focus_ptr_.FlushForTesting(); + return result; + } + MediaInternals::UpdateCallback update_cb_; private: @@ -403,6 +422,8 @@ base::Lock lock_; std::unique_ptr<base::RunLoop> run_loop_; std::unique_ptr<TestBrowserContext> browser_context_; + + media_session::mojom::AudioFocusManagerPtr audio_focus_ptr_; }; TEST_F(MediaInternalsAudioFocusTest, AudioFocusStateIsUpdated) { @@ -413,10 +434,13 @@ media_session1->RequestSystemAudioFocus(AudioFocusType::kGain); WaitForCallbackCount(1); + // Get the |request_id| for the top session. + std::string request_id1 = GetRequestIdForTopFocusRequest(); + // Check JSON is what we expect. { base::DictionaryValue expected_session; - expected_session.SetKey("id", base::Value(0)); + expected_session.SetKey("id", base::Value(request_id1)); expected_session.SetKey("name", GetAddressAsValue(media_session1)); expected_session.SetKey("owner", base::Value(kTestTitle1)); expected_session.SetKey("state", base::Value("Active")); @@ -434,16 +458,20 @@ AudioFocusType::kGainTransientMayDuck); WaitForCallbackCount(2); + // Get the |request_id| for the top session. + std::string request_id2 = GetRequestIdForTopFocusRequest(); + DCHECK_NE(request_id1, request_id2); + // Check JSON is what we expect. { base::DictionaryValue expected_session1; - expected_session1.SetKey("id", base::Value(1)); + expected_session1.SetKey("id", base::Value(request_id2)); expected_session1.SetKey("name", GetAddressAsValue(media_session2)); expected_session1.SetKey("owner", base::Value(kTestTitle2)); expected_session1.SetKey("state", base::Value("Active")); base::DictionaryValue expected_session2; - expected_session2.SetKey("id", base::Value(0)); + expected_session2.SetKey("id", base::Value(request_id1)); expected_session2.SetKey("name", GetAddressAsValue(media_session1)); expected_session2.SetKey("owner", base::Value(kTestTitle1)); expected_session2.SetKey("state", base::Value("Active Ducked")); @@ -461,7 +489,7 @@ // Check JSON is what we expect. { base::DictionaryValue expected_session; - expected_session.SetKey("id", base::Value(0)); + expected_session.SetKey("id", base::Value(request_id1)); expected_session.SetKey("name", GetAddressAsValue(media_session1)); expected_session.SetKey("owner", base::Value(kTestTitle1)); expected_session.SetKey("state", base::Value("Active"));
diff --git a/content/browser/renderer_host/clipboard_host_impl.cc b/content/browser/renderer_host/clipboard_host_impl.cc index 60928166..0b8dc15 100644 --- a/content/browser/renderer_host/clipboard_host_impl.cc +++ b/content/browser/renderer_host/clipboard_host_impl.cc
@@ -6,11 +6,13 @@ #include <utility> +#include "base/location.h" #include "base/macros.h" #include "base/pickle.h" +#include "base/sequenced_task_runner.h" #include "base/strings/utf_string_conversions.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "build/build_config.h" -#include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/system/platform_handle.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard.h" @@ -20,15 +22,23 @@ namespace content { -ClipboardHostImpl::ClipboardHostImpl() - : clipboard_(ui::Clipboard::GetForCurrentThread()), +ClipboardHostImpl::ClipboardHostImpl(blink::mojom::ClipboardHostRequest request) + : binding_(this, std::move(request)), + clipboard_(ui::Clipboard::GetForCurrentThread()), clipboard_writer_( new ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE)) {} void ClipboardHostImpl::Create(blink::mojom::ClipboardHostRequest request) { - mojo::MakeStrongBinding( - base::WrapUnique<ClipboardHostImpl>(new ClipboardHostImpl()), - std::move(request)); + // Clipboard implementations do interesting things, like run nested message + // loops. Since StrongBinding<T> synchronously destroys on failure, that can + // result in some unfortunate use-after-frees after the nested message loops + // exit. + auto* host = new ClipboardHostImpl(std::move(request)); + host->binding_.set_connection_error_handler(base::BindOnce( + [](ClipboardHostImpl* host) { + base::SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, host); + }, + host)); } ClipboardHostImpl::~ClipboardHostImpl() {
diff --git a/content/browser/renderer_host/clipboard_host_impl.h b/content/browser/renderer_host/clipboard_host_impl.h index f9c6a3d..82a0d6b 100644 --- a/content/browser/renderer_host/clipboard_host_impl.h +++ b/content/browser/renderer_host/clipboard_host_impl.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "build/build_config.h" #include "content/common/content_export.h" +#include "mojo/public/cpp/bindings/binding.h" #include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h" #include "ui/base/clipboard/clipboard.h" @@ -33,7 +34,7 @@ private: friend class ClipboardHostImplTest; - ClipboardHostImpl(); + explicit ClipboardHostImpl(blink::mojom::ClipboardHostRequest request); // content::mojom::ClipboardHost void GetSequenceNumber(ui::ClipboardType clipboard_type, @@ -73,7 +74,8 @@ void WriteStringToFindPboard(const base::string16& text) override; #endif - ui::Clipboard* clipboard_; // Not owned + mojo::Binding<blink::mojom::ClipboardHost> binding_; + ui::Clipboard* const clipboard_; // Not owned std::unique_ptr<ui::ScopedClipboardWriter> clipboard_writer_; };
diff --git a/content/browser/renderer_host/clipboard_host_impl_unittest.cc b/content/browser/renderer_host/clipboard_host_impl_unittest.cc index a3a0e92..50b866d 100644 --- a/content/browser/renderer_host/clipboard_host_impl_unittest.cc +++ b/content/browser/renderer_host/clipboard_host_impl_unittest.cc
@@ -7,8 +7,12 @@ #include <stddef.h> #include <stdint.h> +#include "base/callback_helpers.h" #include "base/run_loop.h" +#include "base/strings/string16.h" +#include "base/test/bind_test_util.h" #include "content/public/test/test_browser_thread_bundle.h" +#include "mojo/public/cpp/system/message_pipe.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/test/test_clipboard.h" @@ -19,26 +23,21 @@ class ClipboardHostImplTest : public ::testing::Test { protected: ClipboardHostImplTest() - : clipboard_(ui::TestClipboard::CreateForCurrentThread()) {} + : clipboard_(ui::TestClipboard::CreateForCurrentThread()) { + ClipboardHostImpl::Create(mojo::MakeRequest(&ptr_)); + } ~ClipboardHostImplTest() override { ui::Clipboard::DestroyClipboardForCurrentThread(); } - void CallWriteImage(const SkBitmap& bitmap) { - host_.WriteImage(ui::CLIPBOARD_TYPE_COPY_PASTE, bitmap); - } + blink::mojom::ClipboardHostPtr& mojo_clipboard() { return ptr_; } - void CallCommitWrite() { - host_.CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE); - base::RunLoop().RunUntilIdle(); - } - - ui::Clipboard* clipboard() { return clipboard_; } + ui::Clipboard* system_clipboard() { return clipboard_; } private: const TestBrowserThreadBundle thread_bundle_; - ClipboardHostImpl host_; + blink::mojom::ClipboardHostPtr ptr_; ui::Clipboard* const clipboard_; }; @@ -47,20 +46,48 @@ SkBitmap bitmap; bitmap.allocN32Pixels(3, 2); bitmap.eraseARGB(255, 0, 255, 0); - CallWriteImage(bitmap); + mojo_clipboard()->WriteImage(ui::CLIPBOARD_TYPE_COPY_PASTE, bitmap); uint64_t sequence_number = - clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE); - CallCommitWrite(); + system_clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE); + mojo_clipboard()->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE); + base::RunLoop().RunUntilIdle(); - EXPECT_NE(sequence_number, - clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE)); - EXPECT_FALSE(clipboard()->IsFormatAvailable( + EXPECT_NE(sequence_number, system_clipboard()->GetSequenceNumber( + ui::CLIPBOARD_TYPE_COPY_PASTE)); + EXPECT_FALSE(system_clipboard()->IsFormatAvailable( ui::Clipboard::GetPlainTextFormatType(), ui::CLIPBOARD_TYPE_COPY_PASTE)); - EXPECT_TRUE(clipboard()->IsFormatAvailable( + EXPECT_TRUE(system_clipboard()->IsFormatAvailable( ui::Clipboard::GetBitmapFormatType(), ui::CLIPBOARD_TYPE_COPY_PASTE)); - SkBitmap actual = clipboard()->ReadImage(ui::CLIPBOARD_TYPE_COPY_PASTE); + SkBitmap actual = + system_clipboard()->ReadImage(ui::CLIPBOARD_TYPE_COPY_PASTE); EXPECT_TRUE(gfx::BitmapsAreEqual(bitmap, actual)); } +TEST_F(ClipboardHostImplTest, ReentrancyInSyncCall) { + // Due to the nature of this test, it's somewhat racy. On some platforms + // (currently Linux), reading the clipboard requires running a nested message + // loop. During that time, it's possible to send a bad message that causes the + // message pipe to be closed. Make sure ClipboardHostImpl doesn't UaF |this| + // after exiting the nested message loop. + + // ReadText() is a sync method, so normally, one wouldn't call this method + // directly. These are not normal times though... + base::RunLoop run_loop; + mojo_clipboard()->ReadText( + ui::CLIPBOARD_TYPE_COPY_PASTE, + base::BindLambdaForTesting( + [&run_loop](const base::string16& ignored) { run_loop.Quit(); })); + + // Now purposely write a raw message which (hopefully) won't deserialize to + // anything valid. The receiver side should still be in the midst of + // dispatching ReadText() when Mojo attempts to deserialize this message, + // which should cause a validation failure that signals a connection error. + mojo::WriteMessageRaw(mojo_clipboard().internal_state()->handle(), "moo", 3, + nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); + run_loop.Run(); + + EXPECT_TRUE(mojo_clipboard().encountered_error()); +} + } // namespace content
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index f761c11a..7190d3c 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -112,11 +112,8 @@ void BeginMainFrameNotExpectedSoon() override {} void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override {} void UpdateLayerTreeHost() override; - void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) override {} + void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override { + } void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel, bool has_scrolled_by_touch) override {} void RequestNewLayerTreeFrameSink() override;
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc index 09c612c..f4bef21 100644 --- a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc +++ b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc
@@ -57,8 +57,7 @@ plugin_path_(plugin_path), profile_data_directory_(profile_data_directory), in_process_(in_process), - external_plugin_(external_plugin), - ssl_context_helper_(new SSLContextHelper()) { + external_plugin_(external_plugin) { message_filter_ = new HostMessageFilter(ppapi_host_.get(), this); ppapi_host_->AddHostFactoryFilter(std::unique_ptr<ppapi::host::HostFactory>( new ContentBrowserPepperHostFactory(this)));
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h index 8aeaed4..e892474 100644 --- a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h +++ b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
@@ -18,7 +18,6 @@ #include "base/observer_list.h" #include "base/process/process.h" #include "content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h" -#include "content/browser/renderer_host/pepper/ssl_context_helper.h" #include "content/common/content_export.h" #include "content/common/pepper_renderer_instance_data.h" #include "content/public/browser/browser_ppapi_host.h" @@ -100,10 +99,6 @@ return message_filter_; } - const scoped_refptr<SSLContextHelper>& ssl_context_helper() const { - return ssl_context_helper_; - } - private: friend class BrowserPpapiHostTest; @@ -153,8 +148,6 @@ // BrowserPpapiHost::CreateExternalPluginProcess. bool external_plugin_; - scoped_refptr<SSLContextHelper> ssl_context_helper_; - // Tracks all PP_Instances in this plugin and associated data. std::unordered_map<PP_Instance, std::unique_ptr<InstanceData>> instance_map_;
diff --git a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc index 782cd8b7..69eb47a8 100644 --- a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc +++ b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc
@@ -246,12 +246,18 @@ ContentBrowserPepperHostFactory::CreateAcceptedTCPSocket( PP_Instance instance, ppapi::TCPSocketVersion version, - std::unique_ptr<net::TCPSocket> socket) { + network::mojom::TCPConnectedSocketPtrInfo connected_socket, + network::mojom::SocketObserverRequest socket_observer_request, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream) { if (!CanCreateSocket()) return std::unique_ptr<ppapi::host::ResourceHost>(); - scoped_refptr<ppapi::host::ResourceMessageFilter> tcp_socket( - new PepperTCPSocketMessageFilter(host_, instance, version, - std::move(socket))); + scoped_refptr<PepperTCPSocketMessageFilter> tcp_socket( + base::MakeRefCounted<PepperTCPSocketMessageFilter>( + nullptr /* factory */, host_, instance, version)); + tcp_socket->SetConnectedSocket( + std::move(connected_socket), std::move(socket_observer_request), + std::move(receive_stream), std::move(send_stream)); return std::unique_ptr<ppapi::host::ResourceHost>( new ppapi::host::MessageFilterHost(host_->GetPpapiHost(), instance, 0, tcp_socket));
diff --git a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h index d9b3a55..4c75513 100644 --- a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h +++ b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h
@@ -10,10 +10,11 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "net/socket/tcp_socket.h" +#include "mojo/public/cpp/system/data_pipe.h" #include "ppapi/c/pp_resource.h" #include "ppapi/host/host_factory.h" #include "ppapi/shared_impl/ppb_tcp_socket_shared.h" +#include "services/network/public/mojom/tcp_socket.mojom.h" namespace ppapi { class PpapiPermissions; @@ -41,7 +42,10 @@ std::unique_ptr<ppapi::host::ResourceHost> CreateAcceptedTCPSocket( PP_Instance instance, ppapi::TCPSocketVersion version, - std::unique_ptr<net::TCPSocket> socket); + network::mojom::TCPConnectedSocketPtrInfo connected_socket, + network::mojom::SocketObserverRequest socket_observer_request, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream); private: std::unique_ptr<ppapi::host::ResourceHost> CreateNewTCPSocket(
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc index 2373f97..b74462f 100644 --- a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc +++ b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
@@ -17,13 +17,16 @@ #include "content/browser/renderer_host/pepper/pepper_socket_utils.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/storage_partition.h" #include "content/public/common/socket_permission_request.h" +#include "mojo/public/cpp/bindings/callback_helpers.h" +#include "mojo/public/cpp/bindings/interface_request.h" #include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" -#include "net/log/net_log_source.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "ppapi/c/pp_errors.h" -#include "ppapi/c/private/ppb_net_address_private.h" #include "ppapi/host/dispatch_host_message.h" #include "ppapi/host/error_conversion.h" #include "ppapi/host/ppapi_host.h" @@ -32,6 +35,7 @@ #include "ppapi/shared_impl/api_id.h" #include "ppapi/shared_impl/ppb_tcp_socket_shared.h" #include "ppapi/shared_impl/private/net_address_private_impl.h" +#include "services/network/public/mojom/network_context.mojom.h" #if defined(OS_CHROMEOS) #include "chromeos/network/firewall_hole.h" @@ -42,12 +46,15 @@ namespace { -size_t g_num_instances = 0; +static size_t g_num_instances = 0; } // namespace namespace content { +network::mojom::NetworkContext* + PepperTCPServerSocketMessageFilter::network_context_for_testing = nullptr; + PepperTCPServerSocketMessageFilter::PepperTCPServerSocketMessageFilter( ContentBrowserPepperHostFactory* factory, BrowserPpapiHostImpl* host, @@ -57,6 +64,7 @@ factory_(factory), instance_(instance), state_(STATE_BEFORE_LISTENING), + bound_addr_(NetAddressPrivateImpl::kInvalidNetAddress), external_plugin_(host->external_plugin()), private_api_(private_api), render_process_id_(0), @@ -75,19 +83,35 @@ } // static +void PepperTCPServerSocketMessageFilter::SetNetworkContextForTesting( + network::mojom::NetworkContext* network_context) { + network_context_for_testing = network_context; +} + +// static size_t PepperTCPServerSocketMessageFilter::GetNumInstances() { return g_num_instances; } +void PepperTCPServerSocketMessageFilter::OnFilterDestroyed() { + ResourceMessageFilter::OnFilterDestroyed(); + // Need to close all mojo pipes the socket on the UI thread. Calling Close() + // also ensures that future messages will be ignored, so the mojo pipes won't + // be re-created, so after Close() runs, |this| can be safely deleted on the + // IO thread. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&PepperTCPServerSocketMessageFilter::Close, this)); +} + scoped_refptr<base::TaskRunner> PepperTCPServerSocketMessageFilter::OverrideTaskRunnerForMessage( const IPC::Message& message) { switch (message.type()) { case PpapiHostMsg_TCPServerSocket_Listen::ID: - return base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}); case PpapiHostMsg_TCPServerSocket_Accept::ID: case PpapiHostMsg_TCPServerSocket_StopListening::ID: - return base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}); + return base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}); } return nullptr; } @@ -124,16 +148,45 @@ return PP_ERROR_NOACCESS; } - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&PepperTCPServerSocketMessageFilter::DoListen, this, - context->MakeReplyMessageContext(), addr, backlog)); + net::IPAddressBytes address; + uint16_t port; + + if (state_ != STATE_BEFORE_LISTENING || + !NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) { + Close(); + return PP_ERROR_FAILED; + } + + network::mojom::NetworkContext* network_context = network_context_for_testing; + if (!network_context) { + RenderProcessHost* render_process_host = + RenderProcessHost::FromID(render_process_id_); + network_context = + render_process_host->GetStoragePartition()->GetNetworkContext(); + if (!network_context) + return PP_ERROR_FAILED; + } + + state_ = STATE_LISTEN_IN_PROGRESS; + + ppapi::host::ReplyMessageContext reply_context = + context->MakeReplyMessageContext(); + + network_context->CreateTCPServerSocket( + net::IPEndPoint(net::IPAddress(address), port), backlog, + pepper_socket_utils::PepperTCPNetworkAnnotationTag(), + mojo::MakeRequest(&socket_), + mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce(&PepperTCPServerSocketMessageFilter::OnListenCompleted, + base::Unretained(this), reply_context), + net::ERR_FAILED, base::nullopt /* local_addr_out */)); + return PP_OK_COMPLETIONPENDING; } int32_t PepperTCPServerSocketMessageFilter::OnMsgAccept( const ppapi::host::HostMessageContext* context) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(context); if (state_ != STATE_LISTENING) @@ -142,190 +195,192 @@ state_ = STATE_ACCEPT_IN_PROGRESS; ppapi::host::ReplyMessageContext reply_context( context->MakeReplyMessageContext()); - int net_result = socket_->Accept( - &accepted_socket_, &accepted_address_, - base::Bind(&PepperTCPServerSocketMessageFilter::OnAcceptCompleted, - base::Unretained(this), reply_context)); - if (net_result != net::ERR_IO_PENDING) - OnAcceptCompleted(reply_context, net_result); + + network::mojom::SocketObserverPtr socket_observer; + network::mojom::SocketObserverRequest socket_observer_request = + mojo::MakeRequest(&socket_observer); + socket_->Accept( + std::move(socket_observer), + mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce(&PepperTCPServerSocketMessageFilter::OnAcceptCompleted, + base::Unretained(this), reply_context, + std::move(socket_observer_request)), + net::ERR_FAILED, base::nullopt /* remote_addr */, + network::mojom::TCPConnectedSocketPtr(), + mojo::ScopedDataPipeConsumerHandle(), + mojo::ScopedDataPipeProducerHandle())); return PP_OK_COMPLETIONPENDING; } int32_t PepperTCPServerSocketMessageFilter::OnMsgStopListening( const ppapi::host::HostMessageContext* context) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(context); - state_ = STATE_CLOSED; - socket_.reset(); -#if defined(OS_CHROMEOS) - firewall_hole_.reset(); -#endif // defined(OS_CHROMEOS) + Close(); return PP_OK; } -void PepperTCPServerSocketMessageFilter::DoListen( - const ppapi::host::ReplyMessageContext& context, - const PP_NetAddress_Private& addr, - int32_t backlog) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - net::IPAddressBytes address; - uint16_t port; - if (state_ != STATE_BEFORE_LISTENING || - !NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) { - SendListenError(context, PP_ERROR_FAILED); - state_ = STATE_CLOSED; - return; - } - - state_ = STATE_LISTEN_IN_PROGRESS; - - socket_.reset(new net::TCPSocket(nullptr, nullptr, net::NetLogSource())); - int net_result = net::OK; - do { - net::IPEndPoint ip_end_point(net::IPAddress(address), port); - net_result = socket_->Open(ip_end_point.GetFamily()); - if (net_result != net::OK) - break; - net_result = socket_->SetDefaultOptionsForServer(); - if (net_result != net::OK) - break; - net_result = socket_->Bind(ip_end_point); - if (net_result != net::OK) - break; - net_result = socket_->Listen(backlog); - } while (false); - - if (net_result != net::ERR_IO_PENDING) { -#if defined(OS_CHROMEOS) - OpenFirewallHole(context, net_result); -#else - OnListenCompleted(context, net_result); -#endif - } -} - void PepperTCPServerSocketMessageFilter::OnListenCompleted( const ppapi::host::ReplyMessageContext& context, - int net_result) { - if (state_ != STATE_LISTEN_IN_PROGRESS) { + int net_result, + const base::Optional<net::IPEndPoint>& local_addr) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + // Exit early if this is called during Close(). + if (state_ == STATE_CLOSED) { + DCHECK_EQ(net::ERR_FAILED, net_result); SendListenError(context, PP_ERROR_FAILED); - state_ = STATE_CLOSED; return; } + + DCHECK(socket_.is_bound()); + DCHECK_EQ(state_, STATE_LISTEN_IN_PROGRESS); + if (net_result != net::OK) { SendListenError(context, NetErrorToPepperError(net_result)); + socket_.reset(); state_ = STATE_BEFORE_LISTENING; return; } - DCHECK(socket_.get()); - - net::IPEndPoint end_point; - PP_NetAddress_Private addr; - - int32_t pp_result = - NetErrorToPepperError(socket_->GetLocalAddress(&end_point)); - if (pp_result != PP_OK) { - SendListenError(context, pp_result); - state_ = STATE_BEFORE_LISTENING; - return; - } - if (!NetAddressPrivateImpl::IPEndPointToNetAddress( - end_point.address().bytes(), end_point.port(), &addr)) { + if (!local_addr || + !NetAddressPrivateImpl::IPEndPointToNetAddress( + local_addr->address().bytes(), local_addr->port(), &bound_addr_)) { SendListenError(context, PP_ERROR_FAILED); + socket_.reset(); state_ = STATE_BEFORE_LISTENING; return; } - SendListenReply(context, PP_OK, addr); +#if defined(OS_CHROMEOS) + OpenFirewallHole(context, *local_addr); +#else + SendListenReply(context, PP_OK, bound_addr_); state_ = STATE_LISTENING; +#endif } #if defined(OS_CHROMEOS) void PepperTCPServerSocketMessageFilter::OpenFirewallHole( const ppapi::host::ReplyMessageContext& context, - int net_result) { - if (net_result != net::OK) { - return; - } - net::IPEndPoint local_addr; - socket_->GetLocalAddress(&local_addr); - pepper_socket_utils::FirewallHoleOpenCallback callback = - base::Bind(&PepperTCPServerSocketMessageFilter::OnFirewallHoleOpened, - this, context, net_result); + const net::IPEndPoint& local_addr) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + pepper_socket_utils::FirewallHoleOpenCallback callback = base::BindRepeating( + &PepperTCPServerSocketMessageFilter::OnFirewallHoleOpened, this, context); pepper_socket_utils::OpenTCPFirewallHole(local_addr, callback); } void PepperTCPServerSocketMessageFilter::OnFirewallHoleOpened( const ppapi::host::ReplyMessageContext& context, - int32_t net_result, std::unique_ptr<chromeos::FirewallHole> hole) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK_CURRENTLY_ON(BrowserThread::UI); LOG_IF(WARNING, !hole.get()) << "Firewall hole could not be opened."; firewall_hole_.reset(hole.release()); - OnListenCompleted(context, net_result); + + SendListenReply(context, PP_OK, bound_addr_); + state_ = STATE_LISTENING; } #endif // defined(OS_CHROMEOS) void PepperTCPServerSocketMessageFilter::OnAcceptCompleted( const ppapi::host::ReplyMessageContext& context, - int net_result) { - if (state_ != STATE_ACCEPT_IN_PROGRESS) { - SendAcceptError(context, PP_ERROR_FAILED); - state_ = STATE_CLOSED; + network::mojom::SocketObserverRequest socket_observer_request, + int net_result, + const base::Optional<net::IPEndPoint>& remote_addr, + network::mojom::TCPConnectedSocketPtr connected_socket, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + // Exit early if this is called during Close(). + if (state_ == STATE_CLOSED) { + DCHECK_EQ(net::ERR_FAILED, net_result); + SendListenError(context, PP_ERROR_FAILED); return; } - state_ = STATE_LISTENING; + DCHECK_EQ(state_, STATE_ACCEPT_IN_PROGRESS); + state_ = STATE_LISTENING; if (net_result != net::OK) { SendAcceptError(context, NetErrorToPepperError(net_result)); return; } - DCHECK(accepted_socket_.get()); - - net::IPEndPoint ip_end_point_local; - PP_NetAddress_Private local_addr = NetAddressPrivateImpl::kInvalidNetAddress; - PP_NetAddress_Private remote_addr = NetAddressPrivateImpl::kInvalidNetAddress; - - int32_t pp_result = NetErrorToPepperError( - accepted_socket_->GetLocalAddress(&ip_end_point_local)); - if (pp_result != PP_OK) { - SendAcceptError(context, pp_result); + if (!remote_addr || !connected_socket.is_bound()) { + SendAcceptError(context, NetErrorToPepperError(net_result)); return; } + + DCHECK(socket_observer_request.is_pending()); + + PP_NetAddress_Private pp_remote_addr = + NetAddressPrivateImpl::kInvalidNetAddress; + if (!NetAddressPrivateImpl::IPEndPointToNetAddress( - ip_end_point_local.address().bytes(), ip_end_point_local.port(), - &local_addr) || - !NetAddressPrivateImpl::IPEndPointToNetAddress( - accepted_address_.address().bytes(), accepted_address_.port(), - &remote_addr)) { - SendAcceptError(context, PP_ERROR_FAILED); + remote_addr->address().bytes(), remote_addr->port(), + &pp_remote_addr)) { + SendAcceptError(context, PP_ERROR_ADDRESS_INVALID); return; } + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce( + &PepperTCPServerSocketMessageFilter::OnAcceptCompletedOnIOThread, + this, context, connected_socket.PassInterface(), + std::move(socket_observer_request), std::move(receive_stream), + std::move(send_stream), bound_addr_, pp_remote_addr)); +} + +void PepperTCPServerSocketMessageFilter::OnAcceptCompletedOnIOThread( + const ppapi::host::ReplyMessageContext& context, + network::mojom::TCPConnectedSocketPtrInfo connected_socket, + network::mojom::SocketObserverRequest socket_observer_request, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream, + PP_NetAddress_Private pp_local_addr, + PP_NetAddress_Private pp_remote_addr) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + // |factory_| is guaranteed to be non-NULL here. Only those instances created + // in CONNECTED state have a NULL |factory_|, while getting here requires + // LISTENING state. std::unique_ptr<ppapi::host::ResourceHost> host = - factory_->CreateAcceptedTCPSocket(instance_, - ppapi::TCP_SOCKET_VERSION_PRIVATE, - std::move(accepted_socket_)); + factory_->CreateAcceptedTCPSocket( + instance_, ppapi::TCP_SOCKET_VERSION_PRIVATE, + std::move(connected_socket), std::move(socket_observer_request), + std::move(receive_stream), std::move(send_stream)); if (!host) { SendAcceptError(context, PP_ERROR_NOSPACE); return; } - int pending_resource_id = - ppapi_host_->AddPendingResourceHost(std::move(host)); - if (pending_resource_id) { - SendAcceptReply( - context, PP_OK, pending_resource_id, local_addr, remote_addr); + + int pending_host_id = ppapi_host_->AddPendingResourceHost(std::move(host)); + if (pending_host_id) { + SendAcceptReply(context, PP_OK, pending_host_id, pp_local_addr, + pp_remote_addr); } else { SendAcceptError(context, PP_ERROR_NOSPACE); } } +void PepperTCPServerSocketMessageFilter::Close() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + // This needs to be the first line, so if closing Mojo pipes results in + // invoking any callbacks, they can exit early. + state_ = STATE_CLOSED; + + socket_.reset(); +#if defined(OS_CHROMEOS) + firewall_hole_.reset(); +#endif // defined(OS_CHROMEOS) +} + void PepperTCPServerSocketMessageFilter::SendListenReply( const ppapi::host::ReplyMessageContext& context, int32_t pp_result,
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h index 9c7be218..482d7450 100644 --- a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h +++ b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
@@ -13,20 +13,27 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/optional.h" #include "build/build_config.h" #include "content/common/content_export.h" +#include "mojo/public/cpp/system/data_pipe.h" #include "net/base/ip_endpoint.h" -#include "net/socket/tcp_socket.h" #include "ppapi/c/pp_instance.h" +#include "ppapi/c/private/ppb_net_address_private.h" #include "ppapi/host/resource_message_filter.h" - -struct PP_NetAddress_Private; +#include "services/network/public/mojom/tcp_socket.mojom.h" #if defined(OS_CHROMEOS) #include "chromeos/network/firewall_hole.h" #include "content/public/browser/browser_thread.h" #endif // defined(OS_CHROMEOS) +namespace network { +namespace mojom { +class NetworkContext; +} +} // namespace network + namespace ppapi { namespace host { class PpapiHost; @@ -48,6 +55,11 @@ PP_Instance instance, bool private_api); + // Sets a global NetworkContext object to be used instead of the real one for + // doing all network operations. + static void SetNetworkContextForTesting( + network::mojom::NetworkContext* network_context); + static size_t GetNumInstances(); protected: @@ -63,6 +75,7 @@ }; // ppapi::host::ResourceMessageFilter overrides. + void OnFilterDestroyed() override; scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage( const IPC::Message& message) override; int32_t OnResourceMessageReceived( @@ -76,13 +89,31 @@ int32_t OnMsgStopListening(const ppapi::host::HostMessageContext* context); void DoListen(const ppapi::host::ReplyMessageContext& context, - const PP_NetAddress_Private& addr, int32_t backlog); void OnListenCompleted(const ppapi::host::ReplyMessageContext& context, - int net_result); - void OnAcceptCompleted(const ppapi::host::ReplyMessageContext& context, - int net_result); + int net_result, + const base::Optional<net::IPEndPoint>& local_addr); + void OnAcceptCompleted( + const ppapi::host::ReplyMessageContext& context, + network::mojom::SocketObserverRequest socket_observer_request, + int net_result, + const base::Optional<net::IPEndPoint>& remote_addr, + network::mojom::TCPConnectedSocketPtr connected_socket, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream); + void OnAcceptCompletedOnIOThread( + const ppapi::host::ReplyMessageContext& context, + network::mojom::TCPConnectedSocketPtrInfo connected_socket, + network::mojom::SocketObserverRequest socket_observer_request, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream, + PP_NetAddress_Private pp_local_addr, + PP_NetAddress_Private pp_remote_addr); + + // Closes the socket and FirewallHole, if they're open, and prevents + // |this| from being used further, even with a new socket. + void Close(); void SendListenReply(const ppapi::host::ReplyMessageContext& context, int32_t pp_result, @@ -99,9 +130,8 @@ #if defined(OS_CHROMEOS) void OpenFirewallHole(const ppapi::host::ReplyMessageContext& context, - int net_result); + const net::IPEndPoint& local_addr); void OnFirewallHoleOpened(const ppapi::host::ReplyMessageContext& context, - int32_t net_result, std::unique_ptr<chromeos::FirewallHole> hole); #endif // defined(OS_CHROMEOS) @@ -113,9 +143,9 @@ PP_Instance instance_; State state_; - std::unique_ptr<net::TCPSocket> socket_; - std::unique_ptr<net::TCPSocket> accepted_socket_; - net::IPEndPoint accepted_address_; + network::mojom::TCPServerSocketPtr socket_; + + PP_NetAddress_Private bound_addr_; #if defined(OS_CHROMEOS) std::unique_ptr<chromeos::FirewallHole, @@ -130,6 +160,9 @@ int render_process_id_; int render_frame_id_; + // Used in place of the StoragePartition's NetworkContext when non-null. + static network::mojom::NetworkContext* network_context_for_testing; + DISALLOW_COPY_AND_ASSIGN(PepperTCPServerSocketMessageFilter); };
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc index 070667a..044e303 100644 --- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc +++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
@@ -6,7 +6,6 @@ #include <cstring> #include <utility> -#include <vector> #include "base/bind.h" #include "base/location.h" @@ -23,6 +22,8 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/socket_permission_request.h" +#include "mojo/public/cpp/bindings/callback_helpers.h" +#include "mojo/public/cpp/bindings/interface_request.h" #include "net/base/address_family.h" #include "net/base/host_port_pair.h" #include "net/base/io_buffer.h" @@ -30,10 +31,7 @@ #include "net/base/net_errors.h" #include "net/log/net_log_source.h" #include "net/log/net_log_with_source.h" -#include "net/socket/client_socket_factory.h" -#include "net/socket/client_socket_handle.h" -#include "net/socket/ssl_client_socket.h" -#include "net/socket/tcp_client_socket.h" +#include "net/ssl/ssl_info.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "ppapi/host/dispatch_host_message.h" #include "ppapi/host/error_conversion.h" @@ -48,10 +46,10 @@ #endif // defined(OS_CHROMEOS) using ppapi::NetAddressPrivateImpl; -using ppapi::host::NetErrorToPepperError; -using ppapi::proxy::TCPSocketResourceConstants; using ppapi::TCPSocketState; using ppapi::TCPSocketVersion; +using ppapi::host::NetErrorToPepperError; +using ppapi::proxy::TCPSocketResourceConstants; namespace { @@ -61,31 +59,34 @@ namespace content { +network::mojom::NetworkContext* + PepperTCPSocketMessageFilter::network_context_for_testing = nullptr; + PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter( ContentBrowserPepperHostFactory* factory, BrowserPpapiHostImpl* host, PP_Instance instance, TCPSocketVersion version) : version_(version), + host_(host), + factory_(factory), + instance_(instance), external_plugin_(host->external_plugin()), render_process_id_(0), render_frame_id_(0), binding_(this), - host_(host), - factory_(factory), - instance_(instance), + socket_observer_binding_(this), state_(TCPSocketState::INITIAL), - end_of_file_reached_(false), bind_input_addr_(NetAddressPrivateImpl::kInvalidNetAddress), socket_options_(SOCKET_OPTION_NODELAY), rcvbuf_size_(0), sndbuf_size_(0), - address_index_(0), - socket_(new net::TCPSocket(nullptr, nullptr, net::NetLogSource())), - ssl_context_helper_(host->ssl_context_helper()), pending_accept_(false), + pending_read_size_(0), + pending_read_pp_error_(PP_OK_COMPLETIONPENDING), pending_read_on_unthrottle_(false), - pending_read_net_result_(0), + pending_write_bytes_written_(0), + pending_write_pp_error_(PP_OK_COMPLETIONPENDING), is_potentially_secure_plugin_context_( host->IsPotentiallySecurePluginContext(instance)) { DCHECK(host); @@ -93,67 +94,79 @@ ++g_num_tcp_filter_instances; host_->AddInstanceObserver(instance_, this); - if (!host->GetRenderFrameIDsForInstance( - instance, &render_process_id_, &render_frame_id_)) { + is_throttled_ = host_->IsThrottled(instance_); + if (!host->GetRenderFrameIDsForInstance(instance, &render_process_id_, + &render_frame_id_)) { NOTREACHED(); } } -PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter( - BrowserPpapiHostImpl* host, - PP_Instance instance, - TCPSocketVersion version, - std::unique_ptr<net::TCPSocket> socket) - : version_(version), - external_plugin_(host->external_plugin()), - render_process_id_(0), - render_frame_id_(0), - binding_(this), - host_(host), - factory_(nullptr), - instance_(instance), - state_(TCPSocketState::CONNECTED), - end_of_file_reached_(false), - bind_input_addr_(NetAddressPrivateImpl::kInvalidNetAddress), - socket_options_(SOCKET_OPTION_NODELAY), - rcvbuf_size_(0), - sndbuf_size_(0), - address_index_(0), - socket_(std::move(socket)), - ssl_context_helper_(host->ssl_context_helper()), - pending_accept_(false), - pending_read_on_unthrottle_(false), - pending_read_net_result_(0), - is_potentially_secure_plugin_context_( - host->IsPotentiallySecurePluginContext(instance)) { - DCHECK(host); - DCHECK_NE(version, ppapi::TCP_SOCKET_VERSION_1_0); +void PepperTCPSocketMessageFilter::SetConnectedSocket( + network::mojom::TCPConnectedSocketPtrInfo connected_socket, + network::mojom::SocketObserverRequest socket_observer_request, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + // This method grabs a reference to |this|, and releases a reference on the UI + // thread, so something should be holding on to a reference on the current + // thread to prevent the object from being deleted before this method returns. + DCHECK(HasOneRef()); - ++g_num_tcp_filter_instances; - host_->AddInstanceObserver(instance_, this); - if (!host->GetRenderFrameIDsForInstance( - instance, &render_process_id_, &render_frame_id_)) { - NOTREACHED(); - } + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce( + &PepperTCPSocketMessageFilter::SetConnectedSocketOnUIThread, this, + std::move(connected_socket), std::move(socket_observer_request), + std::move(receive_stream), std::move(send_stream))); } PepperTCPSocketMessageFilter::~PepperTCPSocketMessageFilter() { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (host_) host_->RemoveInstanceObserver(instance_, this); - if (socket_) - socket_->Close(); - if (ssl_socket_) - ssl_socket_->Disconnect(); --g_num_tcp_filter_instances; } +void PepperTCPSocketMessageFilter::SetConnectedSocketOnUIThread( + network::mojom::TCPConnectedSocketPtrInfo connected_socket, + network::mojom::SocketObserverRequest socket_observer_request, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_EQ(state_.state(), TCPSocketState::INITIAL); + + state_ = TCPSocketState(TCPSocketState::CONNECTED); + connected_socket_.Bind(std::move(connected_socket)); + socket_observer_binding_.Bind(std::move(socket_observer_request)); + socket_observer_binding_.set_connection_error_handler( + base::BindOnce(&PepperTCPSocketMessageFilter::OnSocketObserverError, + base::Unretained(this))); + + SetStreams(std::move(receive_stream), std::move(send_stream)); +} + +// static +void PepperTCPSocketMessageFilter::SetNetworkContextForTesting( + network::mojom::NetworkContext* network_context) { + network_context_for_testing = network_context; +} + // static size_t PepperTCPSocketMessageFilter::GetNumInstances() { return g_num_tcp_filter_instances; } +void PepperTCPSocketMessageFilter::OnFilterDestroyed() { + ResourceMessageFilter::OnFilterDestroyed(); + // Need to close all mojo pipes the socket on the UI thread. Calling Close() + // also ensures that future messages will be ignored, so the mojo pipes won't + // be re-created, so after Close() runs, |this| can be safely deleted on the + // IO thread. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&PepperTCPSocketMessageFilter::Close, this)); +} + scoped_refptr<base::TaskRunner> PepperTCPSocketMessageFilter::OverrideTaskRunnerForMessage( const IPC::Message& message) { @@ -162,14 +175,13 @@ case PpapiHostMsg_TCPSocket_Connect::ID: case PpapiHostMsg_TCPSocket_ConnectWithNetAddress::ID: case PpapiHostMsg_TCPSocket_Listen::ID: - return base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}); case PpapiHostMsg_TCPSocket_SSLHandshake::ID: case PpapiHostMsg_TCPSocket_Read::ID: case PpapiHostMsg_TCPSocket_Write::ID: case PpapiHostMsg_TCPSocket_Accept::ID: case PpapiHostMsg_TCPSocket_Close::ID: case PpapiHostMsg_TCPSocket_SetOption::ID: - return base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}); + return base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}); } return nullptr; } @@ -201,13 +213,11 @@ } void PepperTCPSocketMessageFilter::OnThrottleStateChanged(bool is_throttled) { - if (pending_read_on_unthrottle_ && !is_throttled) { - DCHECK(read_buffer_); - OnReadCompleted(pending_read_reply_message_context_, - pending_read_net_result_); - DCHECK(!read_buffer_); - pending_read_on_unthrottle_ = false; - } + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce( + &PepperTCPSocketMessageFilter::ThrottleStateChangedOnUIThread, this, + is_throttled)); } void PepperTCPSocketMessageFilter::OnHostDestroyed() { @@ -216,18 +226,86 @@ host_ = nullptr; } +void PepperTCPSocketMessageFilter::ThrottleStateChangedOnUIThread( + bool is_throttled) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + is_throttled_ = is_throttled; + + if (pending_read_on_unthrottle_ && !is_throttled) { + pending_read_on_unthrottle_ = false; + TryRead(); + } +} + void PepperTCPSocketMessageFilter::OnComplete( int result, const base::Optional<net::AddressList>& resolved_addresses) { DCHECK_CURRENTLY_ON(BrowserThread::UI); binding_.Close(); - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&PepperTCPSocketMessageFilter::OnResolveCompleted, this, - result, std::move(resolved_addresses))); + if (!host_resolve_context_.is_valid()) + return; - Release(); // Balances AddRef in OnMsgConnect. + ppapi::host::ReplyMessageContext context = host_resolve_context_; + host_resolve_context_ = ppapi::host::ReplyMessageContext(); + + if (!state_.IsPending(TCPSocketState::CONNECT)) { + DCHECK(state_.state() == TCPSocketState::CLOSED); + SendConnectError(context, PP_ERROR_FAILED); + return; + } + + if (result != net::OK) { + SendConnectError(context, NetErrorToPepperError(result)); + state_.CompletePendingTransition(false); + return; + } + + StartConnect(context, resolved_addresses.value()); +} + +void PepperTCPSocketMessageFilter::OnReadError(int net_error) { + // If this method is called more than once, or |net_error| isn't an allowed + // value, just ignore the message. + if (pending_read_pp_error_ != PP_OK_COMPLETIONPENDING || net_error > 0 || + net_error == net::ERR_IO_PENDING) { + return; + } + + pending_read_pp_error_ = NetErrorToPepperError(net_error); + // Complete pending read with the error message if there's a pending read, and + // the read data pipe has already been closed. If the pipe is still open, need + // to wait until all data has been read before can start failing reads. + if (pending_read_context_.is_valid() && !receive_stream_ && + !pending_read_on_unthrottle_) { + TryRead(); + } +} + +void PepperTCPSocketMessageFilter::OnWriteError(int net_error) { + // If this method is called more than once, or |net_error| isn't an allowed + // value, just ignore the message. + if (pending_write_pp_error_ != PP_OK_COMPLETIONPENDING || net_error > 0 || + net_error == net::ERR_IO_PENDING) { + return; + } + + pending_write_pp_error_ = NetErrorToPepperError(net_error); + // Complete pending write with the error message if there's a pending write, + // and the write data pipe has already been closed. + if (pending_write_context_.is_valid() && !send_stream_) + TryWrite(); +} + +void PepperTCPSocketMessageFilter::OnSocketObserverError() { + // Note that this method may be called while a connection is still being made. + socket_observer_binding_.Close(); + + // Treat this as a read and write error. If read and write errors have already + // been received, these calls will do nothing. + OnReadError(PP_ERROR_FAILED); + OnWriteError(PP_ERROR_FAILED); } int32_t PepperTCPSocketMessageFilter::OnMsgBind( @@ -247,12 +325,45 @@ return PP_ERROR_NOACCESS; } + if (state_.IsPending(TCPSocketState::BIND)) + return PP_ERROR_INPROGRESS; + + if (!state_.IsValidTransition(TCPSocketState::BIND)) + return PP_ERROR_FAILED; + + DCHECK(!bound_socket_); + DCHECK(!connected_socket_); + DCHECK(!server_socket_); + + // Validate address. + net::IPAddressBytes address; + uint16_t port; + if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(net_addr, &address, + &port)) { + state_.DoTransition(TCPSocketState::BIND, false); + return PP_ERROR_ADDRESS_INVALID; + } + + network::mojom::NetworkContext* network_context = GetNetworkContext(); + if (!network_context) + return PP_ERROR_FAILED; + + // The network service doesn't allow binding a socket without first + // specifying if it's going to be used as a read or write socket, + // so just hold onto the address for now, without actually binding anything. bind_input_addr_ = net_addr; - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&PepperTCPSocketMessageFilter::DoBind, this, - context->MakeReplyMessageContext(), net_addr)); + state_.SetPendingTransition(TCPSocketState::BIND); + network_context->CreateTCPBoundSocket( + net::IPEndPoint(net::IPAddress(address), port), + pepper_socket_utils::PepperTCPNetworkAnnotationTag(), + mojo::MakeRequest(&bound_socket_), + mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce(&PepperTCPSocketMessageFilter::OnBindCompleted, + base::Unretained(this), + context->MakeReplyMessageContext()), + net::ERR_FAILED, base::nullopt /* local_addr */)); + return PP_OK_COMPLETIONPENDING; } @@ -268,39 +379,34 @@ return PP_ERROR_NOACCESS; } - SocketPermissionRequest request( - SocketPermissionRequest::TCP_CONNECT, host, port); - if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_, - true /* private_api */, - &request, - render_process_id_, - render_frame_id_)) { + SocketPermissionRequest request(SocketPermissionRequest::TCP_CONNECT, host, + port); + if (!pepper_socket_utils::CanUseSocketAPIs( + external_plugin_, true /* private_api */, &request, + render_process_id_, render_frame_id_)) { return PP_ERROR_NOACCESS; } - RenderProcessHost* render_process_host = - RenderProcessHost::FromID(render_process_id_); - if (!render_process_host) + if (!state_.IsValidTransition(TCPSocketState::CONNECT)) { + NOTREACHED() << "This shouldn't be reached since the renderer only tries " + << "to connect once."; return PP_ERROR_FAILED; - auto* storage_partition = render_process_host->GetStoragePartition(); - // Grab a reference to this class to ensure that it's fully alive if a - // connection error occurs (i.e. ref count is higher than 0 and there's no - // task from ResourceMessageFilterDeleteTraits to delete this object on the IO - // thread pending). Balanced in OnComplete(); - AddRef(); + } + + network::mojom::NetworkContext* network_context = GetNetworkContext(); + if (!network_context) + return PP_ERROR_FAILED; network::mojom::ResolveHostClientPtr client_ptr; binding_.Bind(mojo::MakeRequest(&client_ptr)); binding_.set_connection_error_handler( base::BindOnce(&PepperTCPSocketMessageFilter::OnComplete, base::Unretained(this), net::ERR_FAILED, base::nullopt)); - storage_partition->GetNetworkContext()->ResolveHost( - net::HostPortPair(host, port), nullptr, std::move(client_ptr)); + network_context->ResolveHost(net::HostPortPair(host, port), nullptr, + std::move(client_ptr)); - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&PepperTCPSocketMessageFilter::HostResolvingStarted, this, - context->MakeReplyMessageContext())); + state_.SetPendingTransition(TCPSocketState::CONNECT); + host_resolve_context_ = context->MakeReplyMessageContext(); return PP_OK_COMPLETIONPENDING; } @@ -312,18 +418,28 @@ content::SocketPermissionRequest request = pepper_socket_utils::CreateSocketPermissionRequest( content::SocketPermissionRequest::TCP_CONNECT, net_addr); - if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_, - IsPrivateAPI(), - &request, - render_process_id_, + if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_, IsPrivateAPI(), + &request, render_process_id_, render_frame_id_)) { return PP_ERROR_NOACCESS; } - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&PepperTCPSocketMessageFilter::DoConnectWithNetAddress, - this, context->MakeReplyMessageContext(), net_addr)); + if (!state_.IsValidTransition(TCPSocketState::CONNECT)) + return PP_ERROR_FAILED; + + state_.SetPendingTransition(TCPSocketState::CONNECT); + + net::IPAddressBytes address; + uint16_t port; + if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(net_addr, &address, + &port)) { + state_.CompletePendingTransition(false); + return PP_ERROR_ADDRESS_INVALID; + } + + StartConnect( + context->MakeReplyMessageContext(), + net::AddressList(net::IPEndPoint(net::IPAddress(address), port))); return PP_OK_COMPLETIONPENDING; } @@ -331,103 +447,101 @@ const ppapi::host::HostMessageContext* context, const std::string& server_name, uint16_t server_port, - const std::vector<std::vector<char> >& trusted_certs, - const std::vector<std::vector<char> >& untrusted_certs) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + const std::vector<std::vector<char>>& trusted_certs, + const std::vector<std::vector<char>>& untrusted_certs) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); // Allow to do SSL handshake only if currently the socket has been connected // and there isn't pending read or write. if (!state_.IsValidTransition(TCPSocketState::SSL_CONNECT) || - read_buffer_.get() || write_buffer_base_.get() || write_buffer_.get()) { + pending_read_context_.is_valid() || pending_write_context_.is_valid()) { return PP_ERROR_FAILED; } + // If there's a pending read or write error, fail the request with that. + if (pending_read_pp_error_ != PP_OK_COMPLETIONPENDING) { + if (pending_read_pp_error_ == PP_OK) + pending_read_pp_error_ = PP_ERROR_FAILED; + return pending_read_pp_error_; + } + + if (pending_write_pp_error_ != PP_OK_COMPLETIONPENDING) { + if (pending_write_pp_error_ == PP_OK) + pending_write_pp_error_ = PP_ERROR_FAILED; + return pending_write_pp_error_; + } + // TODO(raymes,rsleevi): Use trusted/untrusted certificates when connecting. - net::IPEndPoint peer_address; - if (socket_->GetPeerAddress(&peer_address) != net::OK) - return PP_ERROR_FAILED; - std::unique_ptr<net::ClientSocketHandle> handle( - new net::ClientSocketHandle()); - handle->SetSocket(base::WrapUnique<net::StreamSocket>( - new net::TCPClientSocket(std::move(socket_), peer_address))); - net::ClientSocketFactory* factory = - net::ClientSocketFactory::GetDefaultFactory(); - net::HostPortPair host_port_pair(server_name, server_port); - net::SSLClientSocketContext ssl_context; - ssl_context.cert_verifier = ssl_context_helper_->GetCertVerifier(); - ssl_context.transport_security_state = - ssl_context_helper_->GetTransportSecurityState(); - ssl_context.cert_transparency_verifier = - ssl_context_helper_->GetCertTransparencyVerifier(); - ssl_context.ct_policy_enforcer = ssl_context_helper_->GetCTPolicyEnforcer(); - ssl_socket_ = factory->CreateSSLClientSocket( - std::move(handle), host_port_pair, ssl_context_helper_->ssl_config(), - ssl_context); - if (!ssl_socket_) { - LOG(WARNING) << "Failed to create an SSL client socket."; - state_.CompletePendingTransition(false); - return PP_ERROR_FAILED; - } + // Close all Mojo pipes except |connected_socket_|. + receive_stream_.reset(); + read_watcher_.reset(); + send_stream_.reset(); + write_watcher_.reset(); + socket_observer_binding_.Close(); + + network::mojom::SocketObserverPtr socket_observer; + socket_observer_binding_.Bind(mojo::MakeRequest(&socket_observer)); + socket_observer_binding_.set_connection_error_handler( + base::BindOnce(&PepperTCPSocketMessageFilter::OnSocketObserverError, + base::Unretained(this))); state_.SetPendingTransition(TCPSocketState::SSL_CONNECT); - const ppapi::host::ReplyMessageContext reply_context( - context->MakeReplyMessageContext()); - int net_result = ssl_socket_->Connect( - base::BindOnce(&PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted, - base::Unretained(this), reply_context)); - if (net_result != net::ERR_IO_PENDING) - OnSSLHandshakeCompleted(reply_context, net_result); + network::mojom::TLSClientSocketOptionsPtr tls_client_socket_options = + network::mojom::TLSClientSocketOptions::New(); + tls_client_socket_options->send_ssl_info = true; + net::HostPortPair host_port_pair(server_name, server_port); + connected_socket_->UpgradeToTLS( + host_port_pair, std::move(tls_client_socket_options), + pepper_socket_utils::PepperTCPNetworkAnnotationTag(), + mojo::MakeRequest(&tls_client_socket_), std::move(socket_observer), + mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce(&PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted, + base::Unretained(this), + context->MakeReplyMessageContext()), + net::ERR_FAILED, mojo::ScopedDataPipeConsumerHandle(), + mojo::ScopedDataPipeProducerHandle(), base::nullopt /* ssl_info */)); + return PP_OK_COMPLETIONPENDING; } int32_t PepperTCPSocketMessageFilter::OnMsgRead( const ppapi::host::HostMessageContext* context, int32_t bytes_to_read) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!state_.IsConnected() || end_of_file_reached_) + DCHECK_CURRENTLY_ON(BrowserThread::UI); + // This only covers the case where the socket was explicitly closed from the + // caller, or the filter is being destroyed. Read errors and Mojo errors are + // handled in TryRead(). + if (!state_.IsConnected()) return PP_ERROR_FAILED; - if (read_buffer_.get()) + + if (pending_read_context_.is_valid()) return PP_ERROR_INPROGRESS; if (bytes_to_read <= 0 || bytes_to_read > TCPSocketResourceConstants::kMaxReadSize) { return PP_ERROR_BADARGUMENT; } - ppapi::host::ReplyMessageContext reply_context( - context->MakeReplyMessageContext()); - read_buffer_ = base::MakeRefCounted<net::IOBuffer>(bytes_to_read); - - int net_result = net::ERR_FAILED; - if (socket_) { - DCHECK_EQ(state_.state(), TCPSocketState::CONNECTED); - net_result = socket_->Read( - read_buffer_.get(), bytes_to_read, - base::BindOnce(&PepperTCPSocketMessageFilter::OnReadCompleted, - base::Unretained(this), reply_context)); - } else if (ssl_socket_) { - DCHECK_EQ(state_.state(), TCPSocketState::SSL_CONNECTED); - net_result = ssl_socket_->Read( - read_buffer_.get(), bytes_to_read, - base::BindOnce(&PepperTCPSocketMessageFilter::OnReadCompleted, - base::Unretained(this), reply_context)); - } - if (net_result != net::ERR_IO_PENDING) - OnReadCompleted(reply_context, net_result); + pending_read_context_ = context->MakeReplyMessageContext(); + pending_read_size_ = static_cast<uint32_t>(bytes_to_read); + TryRead(); return PP_OK_COMPLETIONPENDING; } int32_t PepperTCPSocketMessageFilter::OnMsgWrite( const ppapi::host::HostMessageContext* context, const std::string& data) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!state_.IsConnected()) return PP_ERROR_FAILED; - if (write_buffer_base_.get() || write_buffer_.get()) + if (pending_write_context_.is_valid()) return PP_ERROR_INPROGRESS; + DCHECK(pending_write_data_.empty()); + DCHECK_EQ(0u, pending_write_bytes_written_); + size_t data_size = data.size(); if (data_size == 0 || data_size > @@ -435,11 +549,9 @@ return PP_ERROR_BADARGUMENT; } - write_buffer_base_ = base::MakeRefCounted<net::IOBuffer>(data_size); - memcpy(write_buffer_base_->data(), data.data(), data_size); - write_buffer_ = base::MakeRefCounted<net::DrainableIOBuffer>( - write_buffer_base_, data_size); - DoWrite(context->MakeReplyMessageContext()); + pending_write_data_ = data; + pending_write_context_ = context->MakeReplyMessageContext(); + TryWrite(); return PP_OK_COMPLETIONPENDING; } @@ -448,6 +560,12 @@ int32_t backlog) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (state_.IsPending(TCPSocketState::LISTEN)) + return PP_ERROR_INPROGRESS; + + if (!state_.IsValidTransition(TCPSocketState::LISTEN)) + return PP_ERROR_FAILED; + // This is only supported by PPB_TCPSocket v1.1 or above. if (version_ != ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE) { NOTREACHED(); @@ -457,59 +575,64 @@ content::SocketPermissionRequest request = pepper_socket_utils::CreateSocketPermissionRequest( content::SocketPermissionRequest::TCP_LISTEN, bind_input_addr_); - if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_, - false /* private_api */, - &request, - render_process_id_, - render_frame_id_)) { + if (!pepper_socket_utils::CanUseSocketAPIs( + external_plugin_, false /* private_api */, &request, + render_process_id_, render_frame_id_)) { return PP_ERROR_NOACCESS; } - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&PepperTCPSocketMessageFilter::DoListen, this, - context->MakeReplyMessageContext(), backlog)); + DCHECK(bound_socket_); + DCHECK(!server_socket_); + + state_.SetPendingTransition(TCPSocketState::LISTEN); + + bound_socket_->Listen( + backlog, mojo::MakeRequest(&server_socket_), + mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce(&PepperTCPSocketMessageFilter::OnListenCompleted, + base::Unretained(this), + context->MakeReplyMessageContext()), + net::ERR_FAILED)); return PP_OK_COMPLETIONPENDING; } int32_t PepperTCPSocketMessageFilter::OnMsgAccept( const ppapi::host::HostMessageContext* context) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK_CURRENTLY_ON(BrowserThread::UI); if (pending_accept_) return PP_ERROR_INPROGRESS; if (state_.state() != TCPSocketState::LISTENING) return PP_ERROR_FAILED; + DCHECK(server_socket_); + pending_accept_ = true; - ppapi::host::ReplyMessageContext reply_context( - context->MakeReplyMessageContext()); - int net_result = socket_->Accept( - &accepted_socket_, &accepted_address_, - base::Bind(&PepperTCPSocketMessageFilter::OnAcceptCompleted, - base::Unretained(this), reply_context)); - if (net_result != net::ERR_IO_PENDING) - OnAcceptCompleted(reply_context, net_result); + + network::mojom::SocketObserverPtr socket_observer; + network::mojom::SocketObserverRequest socket_observer_request = + mojo::MakeRequest(&socket_observer); + server_socket_->Accept( + std::move(socket_observer), + mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce(&PepperTCPSocketMessageFilter::OnAcceptCompleted, + base::Unretained(this), + context->MakeReplyMessageContext(), + std::move(socket_observer_request)), + net::ERR_FAILED, base::nullopt /* remote_addr */, + network::mojom::TCPConnectedSocketPtr(), + mojo::ScopedDataPipeConsumerHandle(), + mojo::ScopedDataPipeProducerHandle())); return PP_OK_COMPLETIONPENDING; } int32_t PepperTCPSocketMessageFilter::OnMsgClose( const ppapi::host::HostMessageContext* context) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK_CURRENTLY_ON(BrowserThread::UI); if (state_.state() == TCPSocketState::CLOSED) return PP_OK; - state_.DoTransition(TCPSocketState::CLOSE, true); -#if defined(OS_CHROMEOS) - // Close the firewall hole, it is no longer needed. - firewall_hole_.reset(); -#endif // defined(OS_CHROMEOS) - // Make sure we get no further callbacks from |socket_| or |ssl_socket_|. - if (socket_) { - socket_->Close(); - } else if (ssl_socket_) { - ssl_socket_->Disconnect(); - } + Close(); return PP_OK; } @@ -517,19 +640,37 @@ const ppapi::host::HostMessageContext* context, PP_TCPSocket_Option name, const ppapi::SocketOptionData& value) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK_CURRENTLY_ON(BrowserThread::UI); + // Options are only applied if |this| is currently being used as a client + // socket, or is going to be used as one - they are ignored for server + // sockets. switch (name) { case PP_TCPSOCKET_OPTION_NO_DELAY: { bool boolean_value = false; if (!value.GetBool(&boolean_value)) return PP_ERROR_BADARGUMENT; - // If the socket is already connected, proxy the value to TCPSocket. - if (state_.state() == TCPSocketState::CONNECTED) - return socket_->SetNoDelay(boolean_value) ? PP_OK : PP_ERROR_FAILED; + // If |connected_socket_| is connecting or has connected, pass the setting + // along. + if (connected_socket_.is_bound()) { + connected_socket_->SetNoDelay( + boolean_value, + // Callback that converts a bool to a net error code which it then + // passes to the common completion callback routine. + base::BindOnce( + [](base::OnceCallback<void(int)> completion_callback, + bool success) { + std::move(completion_callback) + .Run(success ? net::OK : net::ERR_FAILED); + }, + CreateCompletionCallback< + PpapiPluginMsg_TCPSocket_SetOptionReply>(context))); + return PP_OK_COMPLETIONPENDING; + } - // TCPSocket instance is not yet created. So remember the value here. + // TCPConnectedSocket instance is not yet created. So remember the value + // here. if (boolean_value) { socket_options_ |= SOCKET_OPTION_NODELAY; } else { @@ -543,10 +684,14 @@ integer_value > TCPSocketResourceConstants::kMaxSendBufferSize) return PP_ERROR_BADARGUMENT; - // If the socket is already connected, proxy the value to TCPSocket. - if (state_.state() == TCPSocketState::CONNECTED) { - return NetErrorToPepperError( - socket_->SetSendBufferSize(integer_value)); + // If |connected_socket_| is connecting or has connected, pass the setting + // along. + if (connected_socket_.is_bound()) { + connected_socket_->SetSendBufferSize( + integer_value, + CreateCompletionCallback<PpapiPluginMsg_TCPSocket_SetOptionReply>( + context)); + return PP_OK_COMPLETIONPENDING; } // TCPSocket instance is not yet created. So remember the value here. @@ -560,13 +705,18 @@ integer_value > TCPSocketResourceConstants::kMaxReceiveBufferSize) return PP_ERROR_BADARGUMENT; - // If the socket is already connected, proxy the value to TCPSocket. - if (state_.state() == TCPSocketState::CONNECTED) { - return NetErrorToPepperError( - socket_->SetReceiveBufferSize(integer_value)); + // If |connected_socket_| is connecting or has connected, pass the setting + // along. + if (connected_socket_.is_bound()) { + connected_socket_->SetReceiveBufferSize( + integer_value, + CreateCompletionCallback<PpapiPluginMsg_TCPSocket_SetOptionReply>( + context)); + return PP_OK_COMPLETIONPENDING; } - // TCPSocket instance is not yet created. So remember the value here. + // TCPConnectedSocket instance is not yet created. So remember the value + // here. socket_options_ |= SOCKET_OPTION_RCVBUF_SIZE; rcvbuf_size_ = integer_value; return PP_OK; @@ -576,469 +726,498 @@ return PP_ERROR_BADARGUMENT; } } + return PP_OK; } -void PepperTCPSocketMessageFilter::DoBind( - const ppapi::host::ReplyMessageContext& context, - const PP_NetAddress_Private& net_addr) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - if (state_.IsPending(TCPSocketState::BIND)) { - SendBindError(context, PP_ERROR_INPROGRESS); - return; - } - if (!state_.IsValidTransition(TCPSocketState::BIND)) { - SendBindError(context, PP_ERROR_FAILED); - return; - } - - int pp_result = PP_OK; - do { - net::IPAddressBytes address; - uint16_t port; - if (!NetAddressPrivateImpl::NetAddressToIPEndPoint( - net_addr, &address, &port)) { - pp_result = PP_ERROR_ADDRESS_INVALID; - break; - } - net::IPEndPoint bind_addr(net::IPAddress(address), port); - - DCHECK(!socket_->IsValid()); - pp_result = NetErrorToPepperError(socket_->Open(bind_addr.GetFamily())); - if (pp_result != PP_OK) - break; - - pp_result = NetErrorToPepperError(socket_->SetDefaultOptionsForServer()); - if (pp_result != PP_OK) - break; - - pp_result = NetErrorToPepperError(socket_->Bind(bind_addr)); - if (pp_result != PP_OK) - break; - - net::IPEndPoint ip_end_point_local; - pp_result = - NetErrorToPepperError(socket_->GetLocalAddress(&ip_end_point_local)); - if (pp_result != PP_OK) - break; - - PP_NetAddress_Private local_addr = - NetAddressPrivateImpl::kInvalidNetAddress; - if (!NetAddressPrivateImpl::IPEndPointToNetAddress( - ip_end_point_local.address().bytes(), ip_end_point_local.port(), - &local_addr)) { - pp_result = PP_ERROR_ADDRESS_INVALID; - break; - } - - SendBindReply(context, PP_OK, local_addr); - state_.DoTransition(TCPSocketState::BIND, true); - return; - } while (false); - if (socket_->IsValid()) - socket_->Close(); - SendBindError(context, pp_result); - state_.DoTransition(TCPSocketState::BIND, false); -} - -void PepperTCPSocketMessageFilter::HostResolvingStarted( - const ppapi::host::ReplyMessageContext& context) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!state_.IsValidTransition(TCPSocketState::CONNECT)) { - NOTREACHED() << "This shouldn't be reached since the renderer only tries " - << "to connect once."; - SendConnectError(context, PP_ERROR_FAILED); - return; - } - - state_.SetPendingTransition(TCPSocketState::CONNECT); - address_index_ = 0; - address_list_.clear(); - host_resolve_context_ = context; -} - -void PepperTCPSocketMessageFilter::DoConnectWithNetAddress( - const ppapi::host::ReplyMessageContext& context, - const PP_NetAddress_Private& net_addr) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - if (!state_.IsValidTransition(TCPSocketState::CONNECT)) { - SendConnectError(context, PP_ERROR_FAILED); - return; - } - - state_.SetPendingTransition(TCPSocketState::CONNECT); - - net::IPAddressBytes address; - uint16_t port; - if (!NetAddressPrivateImpl::NetAddressToIPEndPoint( - net_addr, &address, &port)) { - state_.CompletePendingTransition(false); - SendConnectError(context, PP_ERROR_ADDRESS_INVALID); - return; - } - - // Copy the single IPEndPoint to address_list_. - address_index_ = 0; - address_list_.clear(); - address_list_.push_back(net::IPEndPoint(net::IPAddress(address), port)); - StartConnect(context); -} - -void PepperTCPSocketMessageFilter::DoWrite( - const ppapi::host::ReplyMessageContext& context) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(write_buffer_base_.get()); - DCHECK(write_buffer_.get()); - DCHECK_GT(write_buffer_->BytesRemaining(), 0); +void PepperTCPSocketMessageFilter::TryRead() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(state_.IsConnected()); + DCHECK(pending_read_context_.is_valid()); + DCHECK_GT(pending_read_size_, 0u); + DCHECK(!pending_read_on_unthrottle_); - int net_result = net::ERR_FAILED; - if (socket_) { - DCHECK_EQ(state_.state(), TCPSocketState::CONNECTED); - net_result = socket_->Write( - write_buffer_.get(), write_buffer_->BytesRemaining(), - base::BindOnce(&PepperTCPSocketMessageFilter::OnWriteCompleted, - base::Unretained(this), context), - static_cast<net::NetworkTrafficAnnotationTag>( - pepper_socket_utils::PepperTCPNetworkAnnotationTag())); - } else if (ssl_socket_) { - DCHECK_EQ(state_.state(), TCPSocketState::SSL_CONNECTED); - net_result = ssl_socket_->Write( - write_buffer_.get(), write_buffer_->BytesRemaining(), - base::BindOnce(&PepperTCPSocketMessageFilter::OnWriteCompleted, - base::Unretained(this), context), - static_cast<net::NetworkTrafficAnnotationTag>( - pepper_socket_utils::PepperTCPNetworkAnnotationTag())); + if (is_throttled_) { + pending_read_on_unthrottle_ = true; + return; } - if (net_result != net::ERR_IO_PENDING) - OnWriteCompleted(context, net_result); + + // This loop's body will generally run only once, unless there's a read error, + // in which case, it will start over, to re-apply the initial logic. + while (true) { + // As long as the read stream is still open, try to read data, even if a + // read error has been received from the SocketObserver, as there may still + // be data on the pipe. + if (!receive_stream_.is_valid()) { + // If no read error has been received yet, wait to receive one through + // the SocketObserver interface. + if (pending_read_pp_error_ == PP_OK_COMPLETIONPENDING) { + DCHECK(socket_observer_binding_.is_bound()); + break; + } + + // Otherwise, pass along the read error. + SendReadError(pending_read_pp_error_); + // If the socket was closed gracefully, only return OK for a single + // read. + if (pending_read_pp_error_ == PP_OK) + pending_read_pp_error_ = PP_ERROR_FAILED; + break; + } + + DCHECK(read_watcher_); + const void* buffer = nullptr; + uint32_t num_bytes = 0; + int mojo_result = receive_stream_->BeginReadData(&buffer, &num_bytes, + MOJO_READ_DATA_FLAG_NONE); + if (mojo_result == MOJO_RESULT_SHOULD_WAIT) { + read_watcher_->ArmOrNotify(); + break; + } + + // On a Mojo pipe error (which may indicate a graceful close, network error, + // or network service crash), close read pipe and restart the loop. + if (mojo_result != MOJO_RESULT_OK) { + read_watcher_.reset(); + receive_stream_.reset(); + continue; + } + + // This is guaranteed by Mojo. + DCHECK_GT(num_bytes, 0u); + + uint32_t bytes_to_copy = std::min(num_bytes, pending_read_size_); + SendReadReply(PP_OK, std::string(reinterpret_cast<const char*>(buffer), + bytes_to_copy)); + receive_stream_->EndReadData(bytes_to_copy); + break; + } } -void PepperTCPSocketMessageFilter::DoListen( - const ppapi::host::ReplyMessageContext& context, - int32_t backlog) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); +void PepperTCPSocketMessageFilter::TryWrite() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(state_.IsConnected()); + DCHECK(pending_write_context_.is_valid()); + DCHECK(!pending_write_data_.empty()); + DCHECK_LT(pending_write_bytes_written_, pending_write_data_.size()); - if (state_.IsPending(TCPSocketState::LISTEN)) { - SendListenReply(context, PP_ERROR_INPROGRESS); - return; + // The structure of this code largely mirrors TryRead() above, with a couple + // differences. The loop will repeat until all bytes are written, there's an + // error, or no more buffer space is available. Also, it's possible for a + // Mojo write to succeed, but a write to the underlying socket to fail. In + // that case, the failure might not be returned to the caller until it tries + // to write again. Since the socket APIs themselves don't guarantee that + // data has been successfully received by the remote server on success, this + // should not cause unexpected problems for consumers. + while (true) { + if (!send_stream_.is_valid()) { + if (pending_write_pp_error_ == PP_OK_COMPLETIONPENDING) { + DCHECK(socket_observer_binding_.is_bound()); + break; + } + SendWriteReply(pending_write_pp_error_); + // Mirror handling of "OK" read errors, only sending "OK" for a single + // write, though getting "OK" from a write is probably nonsense, anyways. + if (pending_write_pp_error_ == PP_OK) + pending_write_pp_error_ = PP_ERROR_FAILED; + break; + } + + DCHECK(write_watcher_); + + uint32_t num_bytes = + pending_write_data_.size() - pending_write_bytes_written_; + DCHECK_GT(num_bytes, 0u); + int mojo_result = send_stream_->WriteData( + pending_write_data_.data() + pending_write_bytes_written_, &num_bytes, + MOJO_WRITE_DATA_FLAG_NONE); + if (mojo_result == MOJO_RESULT_SHOULD_WAIT) { + write_watcher_->ArmOrNotify(); + break; + } + + // On a Mojo pipe error (which may indicate a graceful close, network error, + // or network service crash), close write pipe and restart the loop. + if (mojo_result != MOJO_RESULT_OK) { + write_watcher_.reset(); + send_stream_.reset(); + continue; + } + + // This is guaranteed by Mojo. + DCHECK_GT(num_bytes, 0u); + + pending_write_bytes_written_ += num_bytes; + // If all bytes were written, nothing left to do. + if (pending_write_bytes_written_ == pending_write_data_.size()) { + SendWriteReply(pending_write_bytes_written_); + break; + } } - if (!state_.IsValidTransition(TCPSocketState::LISTEN)) { - SendListenReply(context, PP_ERROR_FAILED); - return; - } - - int32_t pp_result = NetErrorToPepperError(socket_->Listen(backlog)); -#if defined(OS_CHROMEOS) - OpenFirewallHole(context, pp_result); -#else - OnListenCompleted(context, pp_result); -#endif -} - -void PepperTCPSocketMessageFilter::OnResolveCompleted( - int net_result, - const base::Optional<net::AddressList>& resolved_addresses) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!host_resolve_context_.is_valid()) - return; - - ppapi::host::ReplyMessageContext context = host_resolve_context_; - host_resolve_context_ = ppapi::host::ReplyMessageContext(); - - if (!state_.IsPending(TCPSocketState::CONNECT)) { - DCHECK(state_.state() == TCPSocketState::CLOSED); - SendConnectError(context, PP_ERROR_FAILED); - return; - } - - if (net_result != net::OK) { - SendConnectError(context, NetErrorToPepperError(net_result)); - state_.CompletePendingTransition(false); - return; - } - - address_list_ = resolved_addresses.value(); - StartConnect(context); } void PepperTCPSocketMessageFilter::StartConnect( - const ppapi::host::ReplyMessageContext& context) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + const ppapi::host::ReplyMessageContext& context, + const net::AddressList& address_list) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(state_.IsPending(TCPSocketState::CONNECT)); - DCHECK_LT(address_index_, address_list_.size()); + DCHECK(!address_list.empty()); - if (!socket_->IsValid()) { - int net_result = socket_->Open(address_list_[address_index_].GetFamily()); - if (net_result != net::OK) { - OnConnectCompleted(context, net_result); + network::mojom::SocketObserverPtr socket_observer; + socket_observer_binding_.Bind(mojo::MakeRequest(&socket_observer)); + + socket_observer_binding_.set_connection_error_handler( + base::BindOnce(&PepperTCPSocketMessageFilter::OnSocketObserverError, + base::Unretained(this))); + + network::mojom::TCPConnectedSocketOptionsPtr socket_options = + network::mojom::TCPConnectedSocketOptions::New(); + socket_options->no_delay = !!(socket_options_ & SOCKET_OPTION_NODELAY); + if (socket_options_ & SOCKET_OPTION_RCVBUF_SIZE) + socket_options->receive_buffer_size = rcvbuf_size_; + if (socket_options_ & SOCKET_OPTION_SNDBUF_SIZE) + socket_options->send_buffer_size = sndbuf_size_; + + network::mojom::NetworkContext::CreateTCPConnectedSocketCallback callback = + mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce(&PepperTCPSocketMessageFilter::OnConnectCompleted, + base::Unretained(this), context), + net::ERR_FAILED, base::nullopt, base::nullopt, + mojo::ScopedDataPipeConsumerHandle(), + mojo::ScopedDataPipeProducerHandle()); + if (bound_socket_) { + bound_socket_->Connect(address_list, std::move(socket_options), + mojo::MakeRequest(&connected_socket_), + std::move(socket_observer), std::move(callback)); + } else { + network::mojom::NetworkContext* network_context = GetNetworkContext(); + if (!network_context) { + // This will delete |callback|, which will invoke OnConnectCompleted() + // with an error. return; } + network_context->CreateTCPConnectedSocket( + base::nullopt /* local_addr */, address_list, std::move(socket_options), + pepper_socket_utils::PepperTCPNetworkAnnotationTag(), + mojo::MakeRequest(&connected_socket_), std::move(socket_observer), + std::move(callback)); } - - socket_->SetDefaultOptionsForClient(); - - if (!(socket_options_ & SOCKET_OPTION_NODELAY)) { - if (!socket_->SetNoDelay(false)) { - OnConnectCompleted(context, net::ERR_FAILED); - return; - } - } - if (socket_options_ & SOCKET_OPTION_RCVBUF_SIZE) { - int net_result = socket_->SetReceiveBufferSize(rcvbuf_size_); - if (net_result != net::OK) { - OnConnectCompleted(context, net_result); - return; - } - } - if (socket_options_ & SOCKET_OPTION_SNDBUF_SIZE) { - int net_result = socket_->SetSendBufferSize(sndbuf_size_); - if (net_result != net::OK) { - OnConnectCompleted(context, net_result); - return; - } - } - - int net_result = socket_->Connect( - address_list_[address_index_], - base::BindOnce(&PepperTCPSocketMessageFilter::OnConnectCompleted, - base::Unretained(this), context)); - if (net_result != net::ERR_IO_PENDING) - OnConnectCompleted(context, net_result); } void PepperTCPSocketMessageFilter::OnConnectCompleted( const ppapi::host::ReplyMessageContext& context, - int net_result) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + int net_result, + const base::Optional<net::IPEndPoint>& local_addr, + const base::Optional<net::IPEndPoint>& peer_addr, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (!state_.IsPending(TCPSocketState::CONNECT)) { - DCHECK(state_.state() == TCPSocketState::CLOSED); - SendConnectError(context, PP_ERROR_FAILED); + int32_t pp_result = NetErrorToPepperError(net_result); + + if (state_.state() == TCPSocketState::CLOSED) { + // If this is called as a result of Close() being invoked and closing the + // pipe, fail the request without doing anything. + DCHECK_EQ(net_result, net::ERR_FAILED); + SendConnectError(context, pp_result); return; } - int32_t pp_result = NetErrorToPepperError(net_result); + DCHECK(state_.IsPending(TCPSocketState::CONNECT)); + do { if (pp_result != PP_OK) break; - net::IPEndPoint ip_end_point_local; - net::IPEndPoint ip_end_point_remote; - pp_result = - NetErrorToPepperError(socket_->GetLocalAddress(&ip_end_point_local)); - if (pp_result != PP_OK) - break; - pp_result = - NetErrorToPepperError(socket_->GetPeerAddress(&ip_end_point_remote)); - if (pp_result != PP_OK) - break; - - PP_NetAddress_Private local_addr = + PP_NetAddress_Private pp_local_addr = NetAddressPrivateImpl::kInvalidNetAddress; - PP_NetAddress_Private remote_addr = + PP_NetAddress_Private pp_remote_addr = NetAddressPrivateImpl::kInvalidNetAddress; - if (!NetAddressPrivateImpl::IPEndPointToNetAddress( - ip_end_point_local.address().bytes(), ip_end_point_local.port(), - &local_addr) || + if (!local_addr || !peer_addr || !NetAddressPrivateImpl::IPEndPointToNetAddress( - ip_end_point_remote.address().bytes(), ip_end_point_remote.port(), - &remote_addr)) { + local_addr->address().bytes(), local_addr->port(), + &pp_local_addr) || + !NetAddressPrivateImpl::IPEndPointToNetAddress( + peer_addr->address().bytes(), peer_addr->port(), &pp_remote_addr)) { pp_result = PP_ERROR_ADDRESS_INVALID; break; } - SendConnectReply(context, PP_OK, local_addr, remote_addr); + SetStreams(std::move(receive_stream), std::move(send_stream)); + + bound_socket_.reset(); + + SendConnectReply(context, PP_OK, pp_local_addr, pp_remote_addr); state_.CompletePendingTransition(true); return; } while (false); - if (version_ == ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE) { - DCHECK_EQ(1u, address_list_.size()); + // Handle errors. - SendConnectError(context, pp_result); - state_.CompletePendingTransition(false); - } else { - // We have to recreate |socket_| because it doesn't allow a second connect - // attempt. We won't lose any state such as bound address or set options, - // because in the private or v1.0 API, connect must be the first operation. - socket_.reset(new net::TCPSocket(nullptr, nullptr, net::NetLogSource())); + // This can happen even when the network service is behaving correctly, as + // we may see the |socket_observer_binding_| closed before receiving an + // error. + pending_read_pp_error_ = PP_OK_COMPLETIONPENDING; + pending_write_pp_error_ = PP_OK_COMPLETIONPENDING; - if (address_index_ + 1 < address_list_.size()) { - DCHECK_EQ(version_, ppapi::TCP_SOCKET_VERSION_PRIVATE); - address_index_++; - StartConnect(context); - } else { - SendConnectError(context, pp_result); - // In order to maintain backward compatibility, allow further attempts to - // connect the socket. - state_ = TCPSocketState(TCPSocketState::INITIAL); - } + Close(); + SendConnectError(context, pp_result); + + if (version_ != ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE) { + // In order to maintain backward compatibility, allow further attempts + // to connect the socket. + state_ = TCPSocketState(TCPSocketState::INITIAL); } } void PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted( const ppapi::host::ReplyMessageContext& context, - int net_result) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + int net_result, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream, + const base::Optional<net::SSLInfo>& ssl_info) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (!state_.IsPending(TCPSocketState::SSL_CONNECT)) { - DCHECK(state_.state() == TCPSocketState::CLOSED); - SendSSLHandshakeReply(context, PP_ERROR_FAILED); + int pp_result = NetErrorToPepperError(net_result); + if (state_.state() == TCPSocketState::CLOSED) { + // If this is called as a result of Close() being invoked and closing the + // pipe, fail the request without doing anything. + DCHECK_EQ(net_result, net::ERR_FAILED); + SendSSLHandshakeReply(context, pp_result, base::nullopt /* ssl_info */); return; } - SendSSLHandshakeReply(context, NetErrorToPepperError(net_result)); - state_.CompletePendingTransition(net_result == net::OK); -} + DCHECK(state_.IsPending(TCPSocketState::SSL_CONNECT)); -void PepperTCPSocketMessageFilter::OnReadCompleted( - const ppapi::host::ReplyMessageContext& context, - int net_result) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(read_buffer_.get()); + if (pp_result == PP_OK && !ssl_info) + pp_result = PP_ERROR_FAILED; - if (host_ && host_->IsThrottled(instance_)) { - pending_read_on_unthrottle_ = true; - pending_read_reply_message_context_ = context; - pending_read_net_result_ = net_result; - return; - } + state_.CompletePendingTransition(pp_result == PP_OK); - if (net_result > 0) { - SendReadReply( - context, PP_OK, std::string(read_buffer_->data(), net_result)); - } else if (net_result == 0) { - end_of_file_reached_ = true; - SendReadReply(context, PP_OK, std::string()); + if (pp_result != PP_OK) { + Close(); } else { - SendReadError(context, NetErrorToPepperError(net_result)); + SetStreams(std::move(receive_stream), std::move(send_stream)); } - read_buffer_ = nullptr; + + SendSSLHandshakeReply(context, pp_result, ssl_info); } -void PepperTCPSocketMessageFilter::OnWriteCompleted( +void PepperTCPSocketMessageFilter::OnBindCompleted( const ppapi::host::ReplyMessageContext& context, - int net_result) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(write_buffer_base_.get()); - DCHECK(write_buffer_.get()); + int net_result, + const base::Optional<net::IPEndPoint>& local_addr) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); - // Note: For partial writes of 0 bytes, don't continue writing to avoid a - // likely infinite loop. - if (net_result > 0) { - write_buffer_->DidConsume(net_result); - if (write_buffer_->BytesRemaining() > 0 && state_.IsConnected()) { - DoWrite(context); - return; - } + int pp_result = NetErrorToPepperError(net_result); + if (state_.state() == TCPSocketState::CLOSED) { + // If this is called as a result of Close() being invoked and closing the + // pipe, fail the request without doing anything. + DCHECK_EQ(net_result, net::ERR_FAILED); + SendBindError(context, pp_result); + return; } - if (net_result >= 0) - SendWriteReply(context, write_buffer_->BytesConsumed()); - else - SendWriteReply(context, NetErrorToPepperError(net_result)); + DCHECK(bound_socket_); + DCHECK(state_.IsPending(TCPSocketState::BIND)); - write_buffer_ = nullptr; - write_buffer_base_ = nullptr; + PP_NetAddress_Private bound_address = + NetAddressPrivateImpl::kInvalidNetAddress; + if (pp_result == PP_OK && + (!local_addr || !NetAddressPrivateImpl::IPEndPointToNetAddress( + local_addr->address().bytes(), local_addr->port(), + &bound_address))) { + pp_result = PP_ERROR_ADDRESS_INVALID; + } + + if (pp_result != PP_OK) { + bound_socket_.reset(); + } else { + bind_output_ip_endpoint_ = *local_addr; + } + + SendBindReply(context, pp_result, bound_address); + state_.CompletePendingTransition(pp_result == PP_OK); } void PepperTCPSocketMessageFilter::OnListenCompleted( const ppapi::host::ReplyMessageContext& context, - int32_t pp_result) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - SendListenReply(context, pp_result); - state_.DoTransition(TCPSocketState::LISTEN, pp_result == PP_OK); -} + int net_result) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); -#if defined(OS_CHROMEOS) -void PepperTCPSocketMessageFilter::OpenFirewallHole( - const ppapi::host::ReplyMessageContext& context, - int32_t pp_result) { - if (pp_result != PP_OK) { + int pp_result = NetErrorToPepperError(net_result); + if (state_.state() == TCPSocketState::CLOSED) { + // If this is called as a result of Close() being invoked and closing the + // pipe, fail the request without doing anything. + DCHECK_EQ(net_result, net::ERR_FAILED); + SendListenReply(context, pp_result); return; } - net::IPEndPoint local_addr; - // Has already been called successfully in DoBind(). - socket_->GetLocalAddress(&local_addr); - pepper_socket_utils::FirewallHoleOpenCallback callback = - base::Bind(&PepperTCPSocketMessageFilter::OnFirewallHoleOpened, this, - context, pp_result); - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&pepper_socket_utils::OpenTCPFirewallHole, local_addr, - callback)); -} + DCHECK(state_.IsPending(TCPSocketState::LISTEN)); -void PepperTCPSocketMessageFilter::OnFirewallHoleOpened( - const ppapi::host::ReplyMessageContext& context, - int32_t result, - std::unique_ptr<chromeos::FirewallHole> hole) { - LOG_IF(WARNING, !hole.get()) << "Firewall hole could not be opened."; - firewall_hole_.reset(hole.release()); - - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&PepperTCPSocketMessageFilter::OnListenCompleted, this, - context, result)); -} +#if defined(OS_CHROMEOS) + if (pp_result == PP_OK) { + OpenFirewallHole(context); + return; + } #endif // defined(OS_CHROMEOS) + SendListenReply(context, pp_result); + state_.CompletePendingTransition(pp_result == PP_OK); + if (pp_result != PP_OK) + Close(); +} + void PepperTCPSocketMessageFilter::OnAcceptCompleted( const ppapi::host::ReplyMessageContext& context, - int net_result) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); + network::mojom::SocketObserverRequest socket_observer_request, + int net_result, + const base::Optional<net::IPEndPoint>& remote_addr, + network::mojom::TCPConnectedSocketPtr connected_socket, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(pending_accept_); pending_accept_ = false; - if (net_result != net::OK) { SendAcceptError(context, NetErrorToPepperError(net_result)); return; } - DCHECK(accepted_socket_.get()); - - net::IPEndPoint ip_end_point_local; - PP_NetAddress_Private local_addr = NetAddressPrivateImpl::kInvalidNetAddress; - PP_NetAddress_Private remote_addr = NetAddressPrivateImpl::kInvalidNetAddress; - - int32_t pp_result = NetErrorToPepperError( - accepted_socket_->GetLocalAddress(&ip_end_point_local)); - if (pp_result != PP_OK) { - SendAcceptError(context, pp_result); + if (!remote_addr || !connected_socket.is_bound()) { + SendAcceptError(context, NetErrorToPepperError(net_result)); return; } + + DCHECK(socket_observer_request.is_pending()); + + PP_NetAddress_Private pp_remote_addr = + NetAddressPrivateImpl::kInvalidNetAddress; + if (!NetAddressPrivateImpl::IPEndPointToNetAddress( - ip_end_point_local.address().bytes(), ip_end_point_local.port(), - &local_addr) || - !NetAddressPrivateImpl::IPEndPointToNetAddress( - accepted_address_.address().bytes(), accepted_address_.port(), - &remote_addr)) { + remote_addr->address().bytes(), remote_addr->port(), + &pp_remote_addr)) { SendAcceptError(context, PP_ERROR_ADDRESS_INVALID); return; } + PP_NetAddress_Private bound_address = + NetAddressPrivateImpl::kInvalidNetAddress; + bool success = NetAddressPrivateImpl::IPEndPointToNetAddress( + bind_output_ip_endpoint_.address().bytes(), + bind_output_ip_endpoint_.port(), &bound_address); + // This conversion should succeed, since it succeeded in OnBindComplete() + // already. + DCHECK(success); + + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&PepperTCPSocketMessageFilter::OnAcceptCompletedOnIOThread, + this, context, connected_socket.PassInterface(), + std::move(socket_observer_request), + std::move(receive_stream), std::move(send_stream), + bound_address, pp_remote_addr)); +} + +void PepperTCPSocketMessageFilter::OnAcceptCompletedOnIOThread( + const ppapi::host::ReplyMessageContext& context, + network::mojom::TCPConnectedSocketPtrInfo connected_socket, + network::mojom::SocketObserverRequest socket_observer_request, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream, + PP_NetAddress_Private pp_local_addr, + PP_NetAddress_Private pp_remote_addr) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + // |factory_| is guaranteed to be non-NULL here. Only those instances created // in CONNECTED state have a NULL |factory_|, while getting here requires // LISTENING state. + DCHECK(factory_); + std::unique_ptr<ppapi::host::ResourceHost> host = - factory_->CreateAcceptedTCPSocket(instance_, version_, - std::move(accepted_socket_)); + factory_->CreateAcceptedTCPSocket( + instance_, version_, std::move(connected_socket), + std::move(socket_observer_request), std::move(receive_stream), + std::move(send_stream)); if (!host) { SendAcceptError(context, PP_ERROR_NOSPACE); return; } + int pending_host_id = host_->GetPpapiHost()->AddPendingResourceHost(std::move(host)); - if (pending_host_id) - SendAcceptReply(context, PP_OK, pending_host_id, local_addr, remote_addr); - else + if (pending_host_id) { + SendAcceptReply(context, PP_OK, pending_host_id, pp_local_addr, + pp_remote_addr); + } else { SendAcceptError(context, PP_ERROR_NOSPACE); + } } +void PepperTCPSocketMessageFilter::SetStreams( + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream) { + DCHECK(!read_watcher_); + DCHECK(!write_watcher_); + + receive_stream_ = std::move(receive_stream); + read_watcher_ = std::make_unique<mojo::SimpleWatcher>( + FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL); + read_watcher_->Watch( + receive_stream_.get(), + MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + base::BindRepeating( + [](PepperTCPSocketMessageFilter* message_filter, + MojoResult /* result */, + const mojo::HandleSignalsState& /* state */) { + // TryRead will correctly handle both cases (data ready to be + // read, and the pipe was closed). + message_filter->TryRead(); + }, + base::Unretained(this))); + + send_stream_ = std::move(send_stream); + write_watcher_ = std::make_unique<mojo::SimpleWatcher>( + FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL); + write_watcher_->Watch( + send_stream_.get(), + MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + base::BindRepeating( + [](PepperTCPSocketMessageFilter* message_filter, + MojoResult /* result */, + const mojo::HandleSignalsState& /* state */) { + // TryRead will correctly handle both cases (data ready to be + // read, and the pipe was closed). + message_filter->TryWrite(); + }, + base::Unretained(this))); +} + +#if defined(OS_CHROMEOS) +void PepperTCPSocketMessageFilter::OpenFirewallHole( + const ppapi::host::ReplyMessageContext& context) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + pepper_socket_utils::FirewallHoleOpenCallback callback = base::BindRepeating( + &PepperTCPSocketMessageFilter::OnFirewallHoleOpened, this, context); + pepper_socket_utils::OpenTCPFirewallHole(bind_output_ip_endpoint_, callback); +} + +void PepperTCPSocketMessageFilter::OnFirewallHoleOpened( + const ppapi::host::ReplyMessageContext& context, + std::unique_ptr<chromeos::FirewallHole> hole) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(state_.IsPending(TCPSocketState::LISTEN)); + LOG_IF(WARNING, !hole.get()) << "Firewall hole could not be opened."; + firewall_hole_.reset(hole.release()); + + SendListenReply(context, PP_OK); + state_.CompletePendingTransition(true); +} +#endif // defined(OS_CHROMEOS) + void PepperTCPSocketMessageFilter::SendBindReply( const ppapi::host::ReplyMessageContext& context, int32_t pp_result, @@ -1071,24 +1250,21 @@ void PepperTCPSocketMessageFilter::SendConnectError( const ppapi::host::ReplyMessageContext& context, int32_t pp_error) { - SendConnectReply(context, - pp_error, - NetAddressPrivateImpl::kInvalidNetAddress, + SendConnectReply(context, pp_error, NetAddressPrivateImpl::kInvalidNetAddress, NetAddressPrivateImpl::kInvalidNetAddress); } void PepperTCPSocketMessageFilter::SendSSLHandshakeReply( const ppapi::host::ReplyMessageContext& context, - int32_t pp_result) { + int32_t pp_result, + const base::Optional<net::SSLInfo>& ssl_info) { ppapi::host::ReplyMessageContext reply_context(context); reply_context.params.set_result(pp_result); ppapi::PPB_X509Certificate_Fields certificate_fields; if (pp_result == PP_OK) { - // Our socket is guaranteed to be an SSL socket if we get here. - net::SSLInfo ssl_info; - ssl_socket_->GetSSLInfo(&ssl_info); - if (ssl_info.cert.get()) { - pepper_socket_utils::GetCertificateFields(*ssl_info.cert.get(), + DCHECK(ssl_info); + if (ssl_info->cert.get()) { + pepper_socket_utils::GetCertificateFields(*ssl_info->cert, &certificate_fields); } } @@ -1096,27 +1272,36 @@ PpapiPluginMsg_TCPSocket_SSLHandshakeReply(certificate_fields)); } -void PepperTCPSocketMessageFilter::SendReadReply( - const ppapi::host::ReplyMessageContext& context, - int32_t pp_result, - const std::string& data) { - ppapi::host::ReplyMessageContext reply_context(context); - reply_context.params.set_result(pp_result); - SendReply(reply_context, PpapiPluginMsg_TCPSocket_ReadReply(data)); +void PepperTCPSocketMessageFilter::SendReadReply(int32_t pp_result, + const std::string& data) { + DCHECK(pending_read_context_.is_valid()); + DCHECK_GT(pending_read_size_, 0u); + + pending_read_context_.params.set_result(pp_result); + SendReply(pending_read_context_, PpapiPluginMsg_TCPSocket_ReadReply(data)); + + pending_read_context_ = ppapi::host::ReplyMessageContext(); + pending_read_size_ = 0; } -void PepperTCPSocketMessageFilter::SendReadError( - const ppapi::host::ReplyMessageContext& context, - int32_t pp_error) { - SendReadReply(context, pp_error, std::string()); +void PepperTCPSocketMessageFilter::SendReadError(int32_t pp_error) { + SendReadReply(pp_error, std::string()); } -void PepperTCPSocketMessageFilter::SendWriteReply( - const ppapi::host::ReplyMessageContext& context, - int32_t pp_result) { - ppapi::host::ReplyMessageContext reply_context(context); - reply_context.params.set_result(pp_result); - SendReply(reply_context, PpapiPluginMsg_TCPSocket_WriteReply()); +void PepperTCPSocketMessageFilter::SendWriteReply(int32_t pp_result) { + DCHECK(pending_write_context_.is_valid()); + DCHECK(!pending_write_data_.empty()); + DCHECK(pp_result <= 0 || + static_cast<uint32_t>(pp_result) == pending_write_data_.size()); + DCHECK(pp_result <= 0 || + static_cast<uint32_t>(pp_result) == pending_write_bytes_written_); + + pending_write_context_.params.set_result(pp_result); + SendReply(pending_write_context_, PpapiPluginMsg_TCPSocket_WriteReply()); + + pending_write_context_ = ppapi::host::ReplyMessageContext(); + pending_write_data_.clear(); + pending_write_bytes_written_ = 0; } void PepperTCPSocketMessageFilter::SendListenReply( @@ -1135,19 +1320,76 @@ const PP_NetAddress_Private& remote_addr) { ppapi::host::ReplyMessageContext reply_context(context); reply_context.params.set_result(pp_result); - SendReply(reply_context, - PpapiPluginMsg_TCPSocket_AcceptReply( - pending_host_id, local_addr, remote_addr)); + SendReply(reply_context, PpapiPluginMsg_TCPSocket_AcceptReply( + pending_host_id, local_addr, remote_addr)); } void PepperTCPSocketMessageFilter::SendAcceptError( const ppapi::host::ReplyMessageContext& context, int32_t pp_error) { - SendAcceptReply(context, - pp_error, - 0, + SendAcceptReply(context, pp_error, 0, NetAddressPrivateImpl::kInvalidNetAddress, NetAddressPrivateImpl::kInvalidNetAddress); } +void PepperTCPSocketMessageFilter::Close() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + // Need to do this first, as destroying Mojo pipes may invoke some of the + // callbacks with failure messages. + state_.DoTransition(TCPSocketState::CLOSE, true); + +#if defined(OS_CHROMEOS) + // Close the firewall hole, it is no longer needed. + firewall_hole_.reset(); +#endif // defined(OS_CHROMEOS) + + // Make sure there are no further callbacks from Mojo, which could end up in a + // double free (Add ref on the UI thread, while a deletion is pending on the + // IO thread), and that they're closed on the correct thread. + bound_socket_.reset(); + connected_socket_.reset(); + tls_client_socket_.reset(); + server_socket_.reset(); + binding_.Close(); + socket_observer_binding_.Close(); + + read_watcher_.reset(); + receive_stream_.reset(); + write_watcher_.reset(); + send_stream_.reset(); +} + +network::mojom::NetworkContext* +PepperTCPSocketMessageFilter::GetNetworkContext() const { + if (network_context_for_testing) + return network_context_for_testing; + + RenderProcessHost* render_process_host = + RenderProcessHost::FromID(render_process_id_); + if (!render_process_host) + return nullptr; + + return render_process_host->GetStoragePartition()->GetNetworkContext(); +} + +template <class ReturnMessage> +base::OnceCallback<void(int result)> +PepperTCPSocketMessageFilter::CreateCompletionCallback( + const ppapi::host::HostMessageContext* context) { + return mojo::WrapCallbackWithDefaultInvokeIfNotRun( + base::BindOnce(&PepperTCPSocketMessageFilter::ReturnResult<ReturnMessage>, + base::Unretained(this), + context->MakeReplyMessageContext()), + net::ERR_FAILED); +} + +template <class ReturnMessage> +void PepperTCPSocketMessageFilter::ReturnResult( + ppapi::host::ReplyMessageContext context, + int net_result) { + context.params.set_result(NetErrorToPepperError(net_result)); + SendReply(context, ReturnMessage()); +} + } // namespace content
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h index 03648b6..ecd25e9 100644 --- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h +++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
@@ -15,32 +15,27 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/optional.h" #include "build/build_config.h" #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h" -#include "content/browser/renderer_host/pepper/ssl_context_helper.h" #include "content/common/content_export.h" #include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/system/data_pipe.h" #include "net/base/address_list.h" #include "net/base/ip_endpoint.h" -#include "net/socket/tcp_socket.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/ppb_tcp_socket.h" #include "ppapi/c/private/ppb_net_address_private.h" #include "ppapi/host/resource_message_filter.h" #include "ppapi/shared_impl/ppb_tcp_socket_shared.h" #include "services/network/public/mojom/network_context.mojom.h" +#include "services/network/public/mojom/tcp_socket.mojom.h" +#include "services/network/public/mojom/tls_socket.mojom.h" #if defined(OS_CHROMEOS) #include "chromeos/network/firewall_hole.h" -#include "content/public/browser/browser_thread.h" #endif // defined(OS_CHROMEOS) -namespace net { -class DrainableIOBuffer; -class IOBuffer; -class SSLClientSocket; -} - namespace ppapi { class SocketOptionData; @@ -54,21 +49,38 @@ class BrowserPpapiHostImpl; class ContentBrowserPepperHostFactory; +// Handles communication between Pepper and TCP socket Mojo interfaces. The Mojo +// interfaces and all class variables live on the UI thread, while the class is +// created on and receives IPCs on the IO thread (The IPCs are then passed to +// the UI thread). class CONTENT_EXPORT PepperTCPSocketMessageFilter : public ppapi::host::ResourceMessageFilter, public BrowserPpapiHostImpl::InstanceObserver, - public network::mojom::ResolveHostClient { + public network::mojom::ResolveHostClient, + public network::mojom::SocketObserver { public: + // |factory| must be non-nullptr unless the consumer immediately calls + // SetConnectedSocket(). SetConnectedSocket() must be a separate method, + // because something must already be holding onto a reference to |this| when a + // task is posted to the UI thread (Which requires grabbing another reference, + // which could potentially be released before the constructor returns). PepperTCPSocketMessageFilter(ContentBrowserPepperHostFactory* factory, BrowserPpapiHostImpl* host, PP_Instance instance, ppapi::TCPSocketVersion version); - // Used for creating already connected sockets. - PepperTCPSocketMessageFilter(BrowserPpapiHostImpl* host, - PP_Instance instance, - ppapi::TCPSocketVersion version, - std::unique_ptr<net::TCPSocket> socket); + // Switches state to CONNECTED using the provided pipes. May only be called + // before any messages are received, + void SetConnectedSocket( + network::mojom::TCPConnectedSocketPtrInfo connected_socket, + network::mojom::SocketObserverRequest socket_observer_request, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream); + + // Sets a global NetworkContext object to be used instead of the real one for + // doing all network operations. + static void SetNetworkContextForTesting( + network::mojom::NetworkContext* network_context); static size_t GetNumInstances(); @@ -81,7 +93,14 @@ ~PepperTCPSocketMessageFilter() override; + void SetConnectedSocketOnUIThread( + network::mojom::TCPConnectedSocketPtrInfo connected_socket, + network::mojom::SocketObserverRequest socket_observer_request, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream); + // ppapi::host::ResourceMessageFilter overrides. + void OnFilterDestroyed() override; scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage( const IPC::Message& message) override; int32_t OnResourceMessageReceived( @@ -92,11 +111,21 @@ void OnThrottleStateChanged(bool is_throttled) override; void OnHostDestroyed() override; + void ThrottleStateChangedOnUIThread(bool is_throttled); + // network::mojom::ResolveHostClient overrides. void OnComplete( int result, const base::Optional<net::AddressList>& resolved_addresses) override; + // network::mojom::SocketObserver overrides. + void OnReadError(int net_error) override; + void OnWriteError(int net_error) override; + + // Called either when the SocketObserver Mojo pipe has an error, or bad data + // is received from it. + void OnSocketObserverError(); + int32_t OnMsgBind(const ppapi::host::HostMessageContext* context, const PP_NetAddress_Private& net_addr); int32_t OnMsgConnect(const ppapi::host::HostMessageContext* context, @@ -123,38 +152,73 @@ PP_TCPSocket_Option name, const ppapi::SocketOptionData& value); - void DoBind(const ppapi::host::ReplyMessageContext& context, - const PP_NetAddress_Private& net_addr); - void HostResolvingStarted(const ppapi::host::ReplyMessageContext& context); - void DoConnectWithNetAddress(const ppapi::host::ReplyMessageContext& context, - const PP_NetAddress_Private& net_addr); - void DoWrite(const ppapi::host::ReplyMessageContext& context); - void DoListen(const ppapi::host::ReplyMessageContext& context, - int32_t backlog); + // Attempts to read up to |pending_read_size_| bytes from |receive_stream_|. + // If any bytes are read, or there's an error, returns that information to + // |pending_read_context_|. + void TryRead(); + + // Attempts to write |pending_write_data_| to |send_stream_|. + // |pending_write_bytes_written_| reflects how much of the data has been + // written to the stream so far. Once all bytes are written, or there's an + // error, returns that information to |pending_write_context_|. + void TryWrite(); void OnResolveCompleted( int net_result, const base::Optional<net::AddressList>& resolved_addresses); - void StartConnect(const ppapi::host::ReplyMessageContext& context); + + // Attempts to connect to all addresses in |address_list| in order. + void StartConnect(const ppapi::host::ReplyMessageContext& context, + const net::AddressList& address_list); void OnConnectCompleted(const ppapi::host::ReplyMessageContext& context, - int net_result); - void OnSSLHandshakeCompleted(const ppapi::host::ReplyMessageContext& context, - int net_result); - void OnReadCompleted(const ppapi::host::ReplyMessageContext& context, - int net_result); - void OnWriteCompleted(const ppapi::host::ReplyMessageContext& context, - int net_result); - void OnAcceptCompleted(const ppapi::host::ReplyMessageContext& context, - int net_result); + int net_result, + const base::Optional<net::IPEndPoint>& local_addr, + const base::Optional<net::IPEndPoint>& peer_addr, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream); + + void OnSSLHandshakeCompleted( + const ppapi::host::ReplyMessageContext& context, + int net_result, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream, + const base::Optional<net::SSLInfo>& ssl_info); void OnListenCompleted(const ppapi::host::ReplyMessageContext& context, - int32_t pp_result); + int net_result); + + void OnBindCompleted(const ppapi::host::ReplyMessageContext& context, + int net_result, + const base::Optional<net::IPEndPoint>& local_addr); + + void OnAcceptCompleted( + const ppapi::host::ReplyMessageContext& context, + network::mojom::SocketObserverRequest socket_observer_request, + int net_result, + const base::Optional<net::IPEndPoint>& remote_addr, + network::mojom::TCPConnectedSocketPtr connected_socket, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream); + + void OnAcceptCompletedOnIOThread( + const ppapi::host::ReplyMessageContext& context, + network::mojom::TCPConnectedSocketPtrInfo connected_socket, + network::mojom::SocketObserverRequest socket_observer_request, + mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream, + PP_NetAddress_Private pp_local_addr, + PP_NetAddress_Private pp_remote_addr); + + // Sets the read/write streams and constructs watchers for them, which are not + // armed until there's an attempt to use them that can't complete + // synchronously. + void SetStreams(mojo::ScopedDataPipeConsumerHandle receive_stream, + mojo::ScopedDataPipeProducerHandle send_stream); + #if defined(OS_CHROMEOS) - void OpenFirewallHole(const ppapi::host::ReplyMessageContext& context, - int32_t pp_result); + void OpenFirewallHole(const ppapi::host::ReplyMessageContext& context); void OnFirewallHoleOpened(const ppapi::host::ReplyMessageContext& context, - int32_t result, std::unique_ptr<chromeos::FirewallHole> hole); #endif // defined(OS_CHROMEOS) @@ -170,14 +234,13 @@ void SendConnectError(const ppapi::host::ReplyMessageContext& context, int32_t pp_error); void SendSSLHandshakeReply(const ppapi::host::ReplyMessageContext& context, - int32_t pp_result); - void SendReadReply(const ppapi::host::ReplyMessageContext& context, - int32_t pp_result, - const std::string& data); - void SendReadError(const ppapi::host::ReplyMessageContext& context, - int32_t pp_error); - void SendWriteReply(const ppapi::host::ReplyMessageContext& context, - int32_t pp_result); + int32_t pp_result, + const base::Optional<net::SSLInfo>& ssl_info); + // The read and write reply messages use the |pending_*_context_| fields, and + // clear fields related to the pending read / write request as needed. + void SendReadReply(int32_t pp_result, const std::string& data); + void SendReadError(int32_t pp_error); + void SendWriteReply(int32_t pp_result); void SendListenReply(const ppapi::host::ReplyMessageContext& context, int32_t pp_result); void SendAcceptReply(const ppapi::host::ReplyMessageContext& context, @@ -188,23 +251,29 @@ void SendAcceptError(const ppapi::host::ReplyMessageContext& context, int32_t pp_error); + // Closes any open Mojo pipe, and prevents new ones from being opened. + void Close(); + + network::mojom::NetworkContext* GetNetworkContext() const; + bool IsPrivateAPI() const { return version_ == ppapi::TCP_SOCKET_VERSION_PRIVATE; } + // These are used to create a callback that: + // 1) if invoked with a network error code, will pass a message of the + // requested type to |context| with the corresponding Pepper error. + // 2) If destroyed without being invoked, will pass a message of the requested + // type to |context| with PP_ERROR_FAILED. + template <class ReturnMessage> + base::OnceCallback<void(int net_result)> CreateCompletionCallback( + const ppapi::host::HostMessageContext* context); + template <class ReturnMessage> + void ReturnResult(ppapi::host::ReplyMessageContext context, int net_result); + // The following fields are used on both the UI and IO thread. const ppapi::TCPSocketVersion version_; - // The following fields are used only on the UI thread. - const bool external_plugin_; - - int render_process_id_; - int render_frame_id_; - - // A reference to |this| must always be taken while |binding_| is bound to - // ensure that if the error callback is called the object is alive. - mojo::Binding<network::mojom::ResolveHostClient> binding_; - // The following fields are used only on the IO thread. // Non-owning ptr. BrowserPpapiHostImpl* host_; @@ -212,22 +281,33 @@ ContentBrowserPepperHostFactory* factory_; PP_Instance instance_; + // The following fields are used only on the UI thread. + const bool external_plugin_; + + // Mirrors state of host_->IsThrottled(), but is on UI thread. + bool is_throttled_; + + int render_process_id_; + int render_frame_id_; + + // A reference to |this| must always be taken while |binding_| is bound to + // ensure that if the error callback is called the object is alive. + mojo::Binding<network::mojom::ResolveHostClient> binding_; + mojo::Binding<network::mojom::SocketObserver> socket_observer_binding_; + ppapi::TCPSocketState state_; - bool end_of_file_reached_; // This is the address requested to bind. Please note that this is not the // bound address. For example, |bind_input_addr_| may have port set to 0. // It is used to check permission for listening. PP_NetAddress_Private bind_input_addr_; -#if defined(OS_CHROMEOS) - std::unique_ptr<chromeos::FirewallHole, - content::BrowserThread::DeleteOnUIThread> - firewall_hole_; -#endif // defined(OS_CHROMEOS) + // The bound address. + net::IPEndPoint bind_output_ip_endpoint_; - // Used for DNS request. - std::unique_ptr<net::HostResolver::Request> request_; +#if defined(OS_CHROMEOS) + std::unique_ptr<chromeos::FirewallHole> firewall_hole_; +#endif // defined(OS_CHROMEOS) // Bitwise-or of SocketOption flags. This stores the state about whether // each option is set before Connect() is called. @@ -237,42 +317,52 @@ int32_t rcvbuf_size_; int32_t sndbuf_size_; - // |address_list_| may store multiple addresses when - // PPB_TCPSocket_Private.Connect() is used, which involves name resolution. - // In that case, we will try each address in the list until a connection is - // successfully established. - net::AddressList address_list_; - // Where we are in the above list. - size_t address_index_; ppapi::host::ReplyMessageContext host_resolve_context_; - // Non-null unless an SSL connection is requested. - std::unique_ptr<net::TCPSocket> socket_; - // Non-null if an SSL connection is requested. - std::unique_ptr<net::SSLClientSocket> ssl_socket_; + // Holds socket if Bind() is called. Will be used to create a connected or + // server socket, depending on the next call. + network::mojom::TCPBoundSocketPtr bound_socket_; + // Holds socket if Connect() is called. + network::mojom::TCPConnectedSocketPtr connected_socket_; + // Holds socket if socket was upgraded to SSL. + network::mojom::TLSClientSocketPtr tls_client_socket_; + // Holds socket if Listen() is called. + network::mojom::TCPServerSocketPtr server_socket_; - scoped_refptr<net::IOBuffer> read_buffer_; - - // TCPSocket::Write() may not always write the full buffer, but we would - // rather have our DoWrite() do so whenever possible. To do this, we may have - // to call the former multiple times for each of the latter. This entails - // using a DrainableIOBuffer, which requires an underlying base IOBuffer. - scoped_refptr<net::IOBuffer> write_buffer_base_; - scoped_refptr<net::DrainableIOBuffer> write_buffer_; - scoped_refptr<SSLContextHelper> ssl_context_helper_; + // Read/write pipes and their watchers. Both the watchers are configured so + // that they must be armed to receive a notification. + mojo::ScopedDataPipeConsumerHandle receive_stream_; + std::unique_ptr<mojo::SimpleWatcher> read_watcher_; + mojo::ScopedDataPipeProducerHandle send_stream_; + std::unique_ptr<mojo::SimpleWatcher> write_watcher_; bool pending_accept_; - std::unique_ptr<net::TCPSocket> accepted_socket_; - net::IPEndPoint accepted_address_; + uint32_t pending_read_size_; + ppapi::host::ReplyMessageContext pending_read_context_; + // This is set to an error other than PP_OK_COMPLETIONPENDING when a read + // error is received through the SocketObserver interface. If the + // SocketObserver interface is destroyed and this still hasn't been changed + // from its initial value of PP_OK_COMPLETIONPENDING, it's set to + // PP_ERROR_FAILED. + int pending_read_pp_error_; // If the plugin is throttled, we defer completing socket reads until // the plugin is unthrottled. bool pending_read_on_unthrottle_; - ppapi::host::ReplyMessageContext pending_read_reply_message_context_; - int pending_read_net_result_; + + std::string pending_write_data_; + // Number of bytes from |pending_write_data_| that have already been written. + // Always less than the size of |pending_write_data_|. + size_t pending_write_bytes_written_; + ppapi::host::ReplyMessageContext pending_write_context_; + // This mirrors |pending_read_pp_error_|. + int pending_write_pp_error_; const bool is_potentially_secure_plugin_context_; + // Used in place of the StoragePartition's NetworkContext when non-null. + static network::mojom::NetworkContext* network_context_for_testing; + DISALLOW_COPY_AND_ASSIGN(PepperTCPSocketMessageFilter); };
diff --git a/content/browser/renderer_host/pepper/ssl_context_helper.cc b/content/browser/renderer_host/pepper/ssl_context_helper.cc deleted file mode 100644 index 1d6fb4c9..0000000 --- a/content/browser/renderer_host/pepper/ssl_context_helper.cc +++ /dev/null
@@ -1,42 +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. - -#include "content/browser/renderer_host/pepper/ssl_context_helper.h" - -#include "net/cert/cert_verifier.h" -#include "net/cert/ct_policy_enforcer.h" -#include "net/cert/multi_log_ct_verifier.h" -#include "net/http/transport_security_state.h" - -namespace content { - -SSLContextHelper::SSLContextHelper() {} - -SSLContextHelper::~SSLContextHelper() {} - -net::CertVerifier* SSLContextHelper::GetCertVerifier() { - if (!cert_verifier_) - cert_verifier_ = net::CertVerifier::CreateDefault(); - return cert_verifier_.get(); -} - -net::TransportSecurityState* SSLContextHelper::GetTransportSecurityState() { - if (!transport_security_state_) - transport_security_state_.reset(new net::TransportSecurityState()); - return transport_security_state_.get(); -} - -net::CTVerifier* SSLContextHelper::GetCertTransparencyVerifier() { - if (!cert_transparency_verifier_) - cert_transparency_verifier_.reset(new net::MultiLogCTVerifier()); - return cert_transparency_verifier_.get(); -} - -net::CTPolicyEnforcer* SSLContextHelper::GetCTPolicyEnforcer() { - if (!ct_policy_enforcer_) - ct_policy_enforcer_.reset(new net::DefaultCTPolicyEnforcer()); - return ct_policy_enforcer_.get(); -} - -} // namespace content
diff --git a/content/browser/renderer_host/pepper/ssl_context_helper.h b/content/browser/renderer_host/pepper/ssl_context_helper.h deleted file mode 100644 index d2b880ec..0000000 --- a/content/browser/renderer_host/pepper/ssl_context_helper.h +++ /dev/null
@@ -1,59 +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. - -#ifndef CONTENT_BROWSER_RENDERER_HOST_PEPPER_SSL_CONTEXT_HELPER_H_ -#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_SSL_CONTEXT_HELPER_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "net/ssl/ssl_config_service.h" - -namespace net { -class CertVerifier; -class CTPolicyEnforcer; -class CTVerifier; -class TransportSecurityState; -} - -namespace content { - -class SSLContextHelper : public base::RefCounted<SSLContextHelper> { - public: - SSLContextHelper(); - - net::CertVerifier* GetCertVerifier(); - net::TransportSecurityState* GetTransportSecurityState(); - net::CTVerifier* GetCertTransparencyVerifier(); - net::CTPolicyEnforcer* GetCTPolicyEnforcer(); - const net::SSLConfig& ssl_config() { return ssl_config_; } - - private: - friend class base::RefCounted<SSLContextHelper>; - - ~SSLContextHelper(); - - // This is lazily created. Users should use GetCertVerifier to retrieve it. - std::unique_ptr<net::CertVerifier> cert_verifier_; - // This is lazily created. Users should use GetTransportSecurityState to - // retrieve it. - std::unique_ptr<net::TransportSecurityState> transport_security_state_; - // This is lazily created. Users should use GetCertTransparencyVerifier to - // retrieve it. - std::unique_ptr<net::CTVerifier> cert_transparency_verifier_; - // This is lazily created. Users should use GetCTPolicyEnforcer to - // retrieve it. - std::unique_ptr<net::CTPolicyEnforcer> ct_policy_enforcer_; - - // The default SSL configuration settings are used, as opposed to Chrome's SSL - // settings. - net::SSLConfig ssl_config_; - - DISALLOW_COPY_AND_ASSIGN(SSLContextHelper); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_SSL_CONTEXT_HELPER_H_
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 07ec546a..41588b0 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -4336,6 +4336,14 @@ return; } + if (!has_recorded_media_stream_frame_depth_metric_ && !visible_clients_ && + media_stream_count_) { + UMA_HISTOGRAM_EXACT_LINEAR( + "BrowserRenderProcessHost.InvisibleMediaStreamFrameDepth", frame_depth_, + 50); + has_recorded_media_stream_frame_depth_metric_ = true; + } + const ChildProcessLauncherPriority priority( visible_clients_ > 0 || base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableRendererBackgrounding),
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index 0f102fe3..f11aa82 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -888,6 +888,9 @@ bool cleanup_corb_exception_for_plugin_upon_destruction_ = false; + // Fields for recording MediaStream UMA. + bool has_recorded_media_stream_frame_depth_metric_ = false; + base::WeakPtrFactory<RenderProcessHostImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(RenderProcessHostImpl);
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h index e34de9d5..88340958 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.h +++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -20,6 +20,7 @@ #include "third_party/blink/public/platform/web_drag_operation.h" #include "third_party/blink/public/platform/web_input_event.h" #include "ui/gfx/native_widget_types.h" +#include "ui/gfx/range/range.h" namespace blink { class WebMouseEvent; @@ -155,6 +156,12 @@ // currently focused frame. virtual void SelectRange(const gfx::Point& base, const gfx::Point& extent) {} +#if defined(OS_MACOSX) + virtual void DidChangeTextSelection(const base::string16& text, + const gfx::Range& range, + size_t offset) {} +#endif + // Request the renderer to Move the caret to the new position. virtual void MoveCaret(const gfx::Point& extent) {}
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 2ed27d80..5c5bcdf 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -1561,7 +1561,16 @@ // Test that the rendering timeout for newly loaded content fires when enough // time passes without receiving a new compositor frame. This test assumes // Surface Synchronization is off. -TEST_F(RenderWidgetHostTest, NewContentRenderingTimeoutWithoutSurfaceSync) { +// Disabled due to flakiness on Android. See https://crbug.com/892700. +#if defined(OS_ANDROID) +#define MAYBE_NewContentRenderingTimeoutWithoutSurfaceSync \ + DISABLED_NewContentRenderingTimeoutWithoutSurfaceSync +#else +#define MAYBE_NewContentRenderingTimeoutWithoutSurfaceSync \ + NewContentRenderingTimeoutWithoutSurfaceSync +#endif +TEST_F(RenderWidgetHostTest, + NewContentRenderingTimeoutWithoutSurfaceSync_MAYBE) { // If Surface Synchronization is on, we have a separate code path for // cancelling new content rendering timeout that is tested separately. if (features::IsSurfaceSynchronizationEnabled())
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 72f5b4178..e155153e 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -299,6 +299,24 @@ return GetTextInputManager()->GetTextSelection(this)->selected_text(); } +base::string16 RenderWidgetHostViewBase::GetSurroundingText() { + if (!GetTextInputManager()) + return base::string16(); + return GetTextInputManager()->GetTextSelection(this)->text(); +} + +gfx::Range RenderWidgetHostViewBase::GetSelectedRange() { + if (!GetTextInputManager()) + return gfx::Range(); + return GetTextInputManager()->GetTextSelection(this)->range(); +} + +size_t RenderWidgetHostViewBase::GetOffsetForSurroundingText() { + if (!GetTextInputManager()) + return 0; + return GetTextInputManager()->GetTextSelection(this)->offset(); +} + void RenderWidgetHostViewBase::SetBackgroundColor(SkColor color) { DCHECK(SkColorGetA(color) == SK_AlphaOPAQUE || SkColorGetA(color) == SK_AlphaTRANSPARENT);
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index 404d277..becc63fa 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -116,6 +116,9 @@ void WasOccluded() override {} void SetIsInVR(bool is_in_vr) override; base::string16 GetSelectedText() override; + base::string16 GetSurroundingText() override; + gfx::Range GetSelectedRange() override; + size_t GetOffsetForSurroundingText() override; bool IsMouseLocked() override; bool LockKeyboard(base::Optional<base::flat_set<ui::DomCode>> codes) override; void SetBackgroundColor(SkColor color) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_cocoa.h b/content/browser/renderer_host/render_widget_host_view_cocoa.h index 12e531d..fc0105d 100644 --- a/content/browser/renderer_host/render_widget_host_view_cocoa.h +++ b/content/browser/renderer_host/render_widget_host_view_cocoa.h
@@ -55,7 +55,6 @@ @interface RenderWidgetHostViewCocoa : ToolTipBaseView<CommandDispatcherTarget, RenderWidgetHostNSViewClientOwner, - NSCandidateListTouchBarItemDelegate, NSTextInputClient> { @private // The communications channel to the RenderWidgetHostViewMac. This pointer is @@ -199,8 +198,6 @@ @property(nonatomic, assign) NSRange markedRange; @property(nonatomic, assign) ui::TextInputType textInputType; -@property(nonatomic, assign) NSSpellChecker* spellCheckerForTesting; - // Common code path for handling begin gesture events. This helper method is // called via different codepaths based on OS version and SDK: // - On 10.11 and later, when linking with the 10.11 SDK, it is called from
diff --git a/content/browser/renderer_host/render_widget_host_view_cocoa.mm b/content/browser/renderer_host/render_widget_host_view_cocoa.mm index 7730617..ee6cde81 100644 --- a/content/browser/renderer_host/render_widget_host_view_cocoa.mm +++ b/content/browser/renderer_host/render_widget_host_view_cocoa.mm
@@ -21,12 +21,10 @@ #include "content/browser/renderer_host/render_widget_host_view_mac.h" #import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h" #import "content/public/browser/render_widget_host_view_mac_delegate.h" -#include "content/public/common/content_features.h" #include "ui/accessibility/platform/ax_platform_node.h" #import "ui/base/clipboard/clipboard_util_mac.h" #import "ui/base/cocoa/appkit_utils.h" #include "ui/base/cocoa/cocoa_base_utils.h" -#import "ui/base/cocoa/touch_bar_util.h" #include "ui/base/ui_base_features.h" #include "ui/display/screen.h" #include "ui/events/event_utils.h" @@ -54,9 +52,6 @@ namespace { -// Touch bar identifier. -NSString* const kWebContentTouchBarId = @"web-content"; - // Whether a keyboard event has been reserved by OSX. BOOL EventIsReservedBySystem(NSEvent* event) { content::SystemHotkeyHelperMac* helper = @@ -124,10 +119,6 @@ @interface RenderWidgetHostViewCocoa () { bool keyboardLockActive_; base::Optional<base::flat_set<ui::DomCode>> lockedKeys_; - - API_AVAILABLE(macos(10.12.2)) - base::scoped_nsobject<NSCandidateListTouchBarItem> candidateListTouchBarItem_; - NSInteger textSuggestionsSequenceNumber_; } - (void)processedWheelEvent:(const blink::WebMouseWheelEvent&)event consumed:(BOOL)consumed; @@ -137,21 +128,13 @@ - (void)windowDidBecomeKey:(NSNotification*)notification; - (void)windowDidResignKey:(NSNotification*)notification; - (void)sendViewBoundsInWindowToClient; -- (void)requestTextSuggestions; - (void)sendWindowFrameInScreenToClient; - (bool)clientIsDisconnected; -- (void)invalidateTouchBar API_AVAILABLE(macos(10.12.2)); - -// NSCandidateListTouchBarItemDelegate implementation -- (void)candidateListTouchBarItem:(NSCandidateListTouchBarItem*)anItem - endSelectingCandidateAtIndex:(NSInteger)index - API_AVAILABLE(macos(10.12.2)); @end @implementation RenderWidgetHostViewCocoa @synthesize markedRange = markedRange_; @synthesize textInputType = textInputType_; -@synthesize spellCheckerForTesting = spellCheckerForTesting_; - (id)initWithClient:(RenderWidgetHostNSViewClient*)client withClientHelper:(RenderWidgetHostNSViewClientHelper*)clientHelper { @@ -208,65 +191,12 @@ client_->OnBoundsInWindowChanged(gfxViewBoundsInWindow, true); } -- (void)requestTextSuggestions { - if (@available(macOS 10.12.2, *)) { - auto* touchBarItem = candidateListTouchBarItem_.get(); - if (!touchBarItem) - return; - NSRange selectionRange = textSelectionRange_.ToNSRange(); - NSString* selectionText = base::SysUTF16ToNSString(textSelectionText_); - selectionRange.location -= textSelectionOffset_; - NSSpellChecker* spell_checker = spellCheckerForTesting_ - ? spellCheckerForTesting_ - : [NSSpellChecker sharedSpellChecker]; - textSuggestionsSequenceNumber_ = [spell_checker - requestCandidatesForSelectedRange:selectionRange - inString:selectionText - types:NSTextCheckingAllSystemTypes - options:nil - inSpellDocumentWithTag:0 - completionHandler:^( - NSInteger sequenceNumber, - NSArray<NSTextCheckingResult*>* candidates) { - dispatch_async(dispatch_get_main_queue(), ^{ - if (sequenceNumber != - textSuggestionsSequenceNumber_) - return; - [touchBarItem setCandidates:candidates - forSelectedRange:selectionRange - inString:selectionText]; - }); - }]; - } -} - - (void)setTextSelectionText:(base::string16)text offset:(size_t)offset range:(gfx::Range)range { textSelectionText_ = text; textSelectionOffset_ = offset; textSelectionRange_ = range; - [self requestTextSuggestions]; -} - -- (void)candidateListTouchBarItem:(NSCandidateListTouchBarItem*)anItem - endSelectingCandidateAtIndex:(NSInteger)index { - if (index == NSNotFound) - return; - NSTextCheckingResult* selectedResult = anItem.candidates[index]; - NSRange replacementRange = selectedResult.range; - replacementRange.location += textSelectionOffset_; - [self insertText:selectedResult.replacementString - replacementRange:replacementRange]; -} - -- (void)setTextInputType:(ui::TextInputType)textInputType { - if (textInputType_ == textInputType) - return; - textInputType_ = textInputType; - - if (@available(macOS 10.12.2, *)) - [self invalidateTouchBar]; } - (base::string16)selectedText { @@ -1912,36 +1842,6 @@ client_->RequestShutdown(); } -- (void)invalidateTouchBar { - candidateListTouchBarItem_.reset(); - self.touchBar = nil; -} - -- (NSTouchBar*)makeTouchBar { - if (textInputType_ != ui::TEXT_INPUT_TYPE_NONE && - textInputType_ != ui::TEXT_INPUT_TYPE_PASSWORD && - (base::FeatureList::IsEnabled(features::kTextSuggestionsTouchBar) || - base::FeatureList::IsEnabled(features::kExperimentalUi))) { - candidateListTouchBarItem_.reset([[NSCandidateListTouchBarItem alloc] - initWithIdentifier:NSTouchBarItemIdentifierCandidateList]); - auto* candidateListItem = candidateListTouchBarItem_.get(); - - candidateListItem.delegate = self; - candidateListItem.client = self; - [self requestTextSuggestions]; - - base::scoped_nsobject<NSTouchBar> scopedTouchBar([[NSTouchBar alloc] init]); - auto* touchBar = scopedTouchBar.get(); - touchBar.customizationIdentifier = ui::GetTouchBarId(kWebContentTouchBarId); - touchBar.templateItems = [NSSet setWithObject:candidateListTouchBarItem_]; - touchBar.defaultItemIdentifiers = - @[ NSTouchBarItemIdentifierCandidateList ]; - return scopedTouchBar.autorelease(); - } - - return [super makeTouchBar]; -} - @end //
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 455a6ccb..94d6e793 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -627,6 +627,9 @@ return; ns_view_bridge_->SetTextSelection(selection->text(), selection->offset(), selection->range()); + if (host() && host()->delegate()) + host()->delegate()->DidChangeTextSelection( + selection->text(), selection->range(), selection->offset()); } bool RenderWidgetHostViewMac::ShouldWaitInPreCommit() {
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm index f6549b3..ed5984e8 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -127,72 +127,6 @@ @end -@interface FakeTextCheckingResult : NSObject<NSCopying> -@property(readonly) NSRange range; -@property(readonly) NSString* replacementString; -@end - -@implementation FakeTextCheckingResult { - base::scoped_nsobject<NSString> replacementString_; -} -@synthesize range = range_; - -+ (FakeTextCheckingResult*)resultWithRange:(NSRange)range - replacementString:(NSString*)replacementString { - FakeTextCheckingResult* result = - [[[FakeTextCheckingResult alloc] init] autorelease]; - result->range_ = range; - result->replacementString_.reset([replacementString retain]); - return result; -} - -- (id)copyWithZone:(NSZone*)zone { - return - [[FakeTextCheckingResult resultWithRange:self.range - replacementString:self.replacementString] retain]; -} - -- (NSString*)replacementString { - return replacementString_; -} -@end - -@interface FakeSpellChecker : NSObject -@property NSInteger sequenceNumber; -@end - -@implementation FakeSpellChecker { - base::mac::ScopedBlock<void (^)(NSInteger sequenceNumber, - NSArray<NSTextCheckingResult*>* candidates)> - lastCompletionHandler_; -} -@synthesize sequenceNumber = sequenceNumber_; - -- (NSInteger) -requestCandidatesForSelectedRange:(NSRange)selectedRange - inString:(NSString*)stringToCheck - types:(NSTextCheckingTypes)checkingTypes - options: - (nullable NSDictionary<NSTextCheckingOptionKey, - id>*)options - inSpellDocumentWithTag:(NSInteger)tag - completionHandler: - (void (^__nullable)(NSInteger sequenceNumber, - NSArray<NSTextCheckingResult*>* - candidates))completionHandler - NS_AVAILABLE_MAC(10_12_2) { - sequenceNumber_ += 1; - lastCompletionHandler_.reset([completionHandler copy]); - return sequenceNumber_; -} - -- (void (^)(NSInteger sequenceNumber, - NSArray<NSTextCheckingResult*>* candidates))lastCompletionHandler { - return lastCompletionHandler_; -} - -@end - namespace content { namespace { @@ -1735,12 +1669,6 @@ RenderWidgetHostImpl* tab_widget() { return widget_; } RenderWidgetHostViewCocoa* tab_cocoa_view() { return view_->cocoa_view(); } - API_AVAILABLE(macos(10.12.2)) - NSCandidateListTouchBarItem* candidate_list_item() { - return [tab_cocoa_view().touchBar - itemForIdentifier:NSTouchBarItemIdentifierCandidateList]; - } - protected: MockRenderProcessHost* process_host_; MockRenderWidgetHostImpl* widget_; @@ -2027,90 +1955,6 @@ EXPECT_FALSE(message->monitor_request()); } -TEST_F(InputMethodMacTest, TouchBarTextSuggestionsDisabled) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(features::kTextSuggestionsTouchBar); - if (@available(macOS 10.12.2, *)) { - EXPECT_NSEQ(nil, candidate_list_item()); - SetTextInputType(tab_view(), ui::TEXT_INPUT_TYPE_TEXT); - EXPECT_NSEQ(nil, candidate_list_item()); - } -} - -TEST_F(InputMethodMacTest, TouchBarTextSuggestionsPresence) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(features::kTextSuggestionsTouchBar); - if (@available(macOS 10.12.2, *)) { - EXPECT_NSEQ(nil, candidate_list_item()); - SetTextInputType(tab_view(), ui::TEXT_INPUT_TYPE_PASSWORD); - EXPECT_NSEQ(nil, candidate_list_item()); - SetTextInputType(tab_view(), ui::TEXT_INPUT_TYPE_TEXT); - EXPECT_NSNE(nil, candidate_list_item()); - } -} - -TEST_F(InputMethodMacTest, TouchBarTextSuggestionsReplacement) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(features::kTextSuggestionsTouchBar); - if (@available(macOS 10.12.2, *)) { - base::scoped_nsobject<FakeSpellChecker> spellChecker( - [[FakeSpellChecker alloc] init]); - tab_cocoa_view().spellCheckerForTesting = - static_cast<NSSpellChecker*>(spellChecker.get()); - - SetTextInputType(tab_view(), ui::TEXT_INPUT_TYPE_TEXT); - EXPECT_NSNE(nil, candidate_list_item()); - - FakeTextCheckingResult* fakeResult = - [FakeTextCheckingResult resultWithRange:NSMakeRange(0, 3) - replacementString:@"foo"]; - - const base::string16 kOriginalString = base::UTF8ToUTF16("abcxxxghi"); - - // Change the selection once; requests completions from the spell checker. - tab_view()->SelectionChanged(kOriginalString, 3, gfx::Range(0, 0)); - - NSInteger firstSequenceNumber = [spellChecker sequenceNumber]; - base::mac::ScopedBlock<void (^)(NSInteger sequenceNumber, - NSArray<NSTextCheckingResult*>* candidates)> - firstCompletionHandler([[spellChecker lastCompletionHandler] retain]); - - EXPECT_NE(nil, (id)firstCompletionHandler.get()); - EXPECT_EQ(0U, candidate_list_item().candidates.count); - - // Instead of replying right away, change the selection again! - tab_view()->SelectionChanged(kOriginalString, 3, gfx::Range(3, 3)); - - EXPECT_NE(firstSequenceNumber, [spellChecker sequenceNumber]); - - // Make sure that calling the stale completion handler is a no-op. - firstCompletionHandler.get()( - firstSequenceNumber, - @[ static_cast<NSTextCheckingResult*>(fakeResult) ]); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0U, candidate_list_item().candidates.count); - - // But calling the current handler should work. - [spellChecker lastCompletionHandler]( - [spellChecker sequenceNumber], - @[ static_cast<NSTextCheckingResult*>(fakeResult) ]); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1U, candidate_list_item().candidates.count); - - base::RunLoop().RunUntilIdle(); - MockWidgetInputHandler::MessageVector events = - host_->GetAndResetDispatchedMessages(); - ASSERT_EQ("", GetMessageNames(events)); - - // Now, select that result. - [tab_cocoa_view() candidateListTouchBarItem:candidate_list_item() - endSelectingCandidateAtIndex:0]; - base::RunLoop().RunUntilIdle(); - events = widget_->GetAndResetDispatchedMessages(); - ASSERT_EQ("CommitText", GetMessageNames(events)); - } -} - TEST_F(RenderWidgetHostViewMacTest, ClearCompositorFrame) { BrowserCompositorMac* browser_compositor = rwhv_mac_->BrowserCompositor(); ui::Compositor* ui_compositor = browser_compositor->GetCompositor();
diff --git a/content/browser/service_worker/service_worker_navigation_loader.cc b/content/browser/service_worker/service_worker_navigation_loader.cc index 9952fc48..8d22338 100644 --- a/content/browser/service_worker/service_worker_navigation_loader.cc +++ b/content/browser/service_worker/service_worker_navigation_loader.cc
@@ -287,6 +287,8 @@ response_head_.load_timing.send_start = now; response_head_.load_timing.send_end = now; + devtools_attached_ = version->embedded_worker()->devtools_attached(); + // Note that we don't record worker preparation time in S13nServiceWorker // path for now. If we want to measure worker preparation time we can // calculate it from response_head_.service_worker_ready_time and @@ -433,7 +435,7 @@ body_as_blob_.Bind(std::move(response->blob->blob)); mojo::ScopedDataPipeConsumerHandle data_pipe; int error = ServiceWorkerLoaderHelpers::ReadBlobResponseBody( - &body_as_blob_, response->blob->size, resource_request_.headers, + &body_as_blob_, response->blob->size, base::BindOnce(&ServiceWorkerNavigationLoader::OnBlobReadingComplete, weak_factory_.GetWeakPtr()), &data_pipe); @@ -530,6 +532,10 @@ !base::TimeTicks::IsConsistentAcrossProcesses()) return; + // Don't record metrics when DevTools is attached to reduce noise. + if (devtools_attached_) + return; + // Time between the request is made and the request is routed to this loader. UMA_HISTOGRAM_TIMES( "ServiceWorker.LoadTiming.MainFrame.MainResource."
diff --git a/content/browser/service_worker/service_worker_navigation_loader.h b/content/browser/service_worker/service_worker_navigation_loader.h index 8f740b9..3e544aa 100644 --- a/content/browser/service_worker/service_worker_navigation_loader.h +++ b/content/browser/service_worker/service_worker_navigation_loader.h
@@ -186,6 +186,7 @@ bool did_navigation_preload_ = false; network::ResourceResponseHead response_head_; + bool devtools_attached_ = false; blink::mojom::ServiceWorkerFetchEventTimingPtr fetch_event_timing_; base::TimeTicks completion_time_;
diff --git a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc index 29ed62539..3cb616e 100644 --- a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc +++ b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
@@ -621,6 +621,10 @@ histogram_tester.ExpectUniqueSample(kHistogramMainResourceFetchEvent, blink::ServiceWorkerStatusCode::kOk, 1); + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "ResponseReceivedToCompleted", + 1); } TEST_F(ServiceWorkerNavigationLoaderTest, NoActiveWorker) { @@ -638,6 +642,10 @@ // No fetch event was dispatched. histogram_tester.ExpectTotalCount(kHistogramMainResourceFetchEvent, 0); + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "StartToForwardServiceWorker", + 0); } // Test that the request body is passed to the fetch event. @@ -663,6 +671,8 @@ } TEST_F(ServiceWorkerNavigationLoaderTest, BlobResponse) { + base::HistogramTester histogram_tester; + // Construct the blob to respond with. const std::string kResponseBody = "Here is sample text for the blob."; auto blob_data = std::make_unique<storage::BlobDataBuilder>("blob-id:myblob"); @@ -694,10 +704,18 @@ mojo::BlockingCopyToString(client_.response_body_release(), &body)); EXPECT_EQ(kResponseBody, body); EXPECT_EQ(net::OK, client_.completion_status().error_code); + + // Test histogram of reading body. + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "ResponseReceivedToCompleted", + 1); } // Tell the helper to respond with a non-existent Blob. TEST_F(ServiceWorkerNavigationLoaderTest, BrokenBlobResponse) { + base::HistogramTester histogram_tester; + const std::string kBrokenUUID = "broken_uuid"; // Create the broken blob. @@ -724,9 +742,21 @@ // the body. client_.RunUntilComplete(); EXPECT_EQ(net::ERR_OUT_OF_MEMORY, client_.completion_status().error_code); + + // Timing histograms shouldn't be recorded on broken response. + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "StartToForwardServiceWorker", + 0); + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "ResponseReceivedToCompleted", + 0); } TEST_F(ServiceWorkerNavigationLoaderTest, StreamResponse) { + base::HistogramTester histogram_tester; + // Construct the Stream to respond with. const char kResponseBody[] = "Here is sample text for the Stream."; blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback; @@ -763,10 +793,18 @@ EXPECT_TRUE( mojo::BlockingCopyToString(client_.response_body_release(), &response)); EXPECT_EQ(kResponseBody, response); + + // Test histogram of reading body. + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "ResponseReceivedToCompleted", + 1); } // Test when a stream response body is aborted. TEST_F(ServiceWorkerNavigationLoaderTest, StreamResponse_Abort) { + base::HistogramTester histogram_tester; + // Construct the Stream to respond with. const char kResponseBody[] = "Here is sample text for the Stream."; blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback; @@ -801,10 +839,22 @@ EXPECT_TRUE( mojo::BlockingCopyToString(client_.response_body_release(), &response)); EXPECT_EQ(kResponseBody, response); + + // Timing histograms shouldn't be recorded on abort. + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "StartToForwardServiceWorker", + 0); + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "ResponseReceivedToCompleted", + 0); } // Test when the loader is cancelled while a stream response is being written. TEST_F(ServiceWorkerNavigationLoaderTest, StreamResponseAndCancel) { + base::HistogramTester histogram_tester; + // Construct the Stream to respond with. const char kResponseBody[] = "Here is sample text for the Stream."; blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback; @@ -846,6 +896,16 @@ client_.RunUntilComplete(); EXPECT_FALSE(data_pipe.consumer_handle.is_valid()); EXPECT_EQ(net::ERR_ABORTED, client_.completion_status().error_code); + + // Timing histograms shouldn't be recorded on cancel. + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "StartToForwardServiceWorker", + 0); + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "ResponseReceivedToCompleted", + 0); } // Test when the service worker responds with network fallback. @@ -868,6 +928,12 @@ EXPECT_FALSE(was_main_resource_load_failed_called_); histogram_tester.ExpectUniqueSample(kHistogramMainResourceFetchEvent, blink::ServiceWorkerStatusCode::kOk, 1); + + // Test histogram of network fallback. + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "FetchHandlerEndToFallbackNetwork", + 1); } // Test when the service worker rejects the FetchEvent. @@ -885,6 +951,11 @@ // Event dispatch still succeeded. histogram_tester.ExpectUniqueSample(kHistogramMainResourceFetchEvent, blink::ServiceWorkerStatusCode::kOk, 1); + // Timing UMAs shouldn't be recorded when we receive an error response. + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "StartToForwardServiceWorker", + 0); } // Test when dispatching the fetch event to the service worker failed. @@ -904,6 +975,11 @@ histogram_tester.ExpectUniqueSample( kHistogramMainResourceFetchEvent, blink::ServiceWorkerStatusCode::kErrorFailed, 1); + // Timing UMAs shouldn't be recorded when failed to dispatch an event. + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "StartToForwardServiceWorker", + 0); } // Test when the respondWith() promise resolves before the waitUntil() promise @@ -957,6 +1033,10 @@ // No fetch event was dispatched. histogram_tester.ExpectTotalCount(kHistogramMainResourceFetchEvent, 0); + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.MainFrame.MainResource." + "StartToForwardServiceWorker", + 0); } // Test responding to the fetch event with the navigation preload response.
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc index 2b4ae78..472a726 100644 --- a/content/browser/service_worker/service_worker_url_request_job.cc +++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -586,7 +586,7 @@ auto blob_builder = std::make_unique<storage::BlobDataBuilder>(base::GenerateGUID()); for (const network::DataElement& element : (*body_->elements())) { - blob_builder->AppendIPCDataElement(element, nullptr, + blob_builder->AppendIPCDataElement(element, blob_storage_context_->registry()); }
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 169aa36..7e93694a 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3246,6 +3246,15 @@ focused_frame->GetFrameInputHandler()->SelectRange(base, extent); } +#if defined(OS_MACOSX) +void WebContentsImpl::DidChangeTextSelection(const base::string16& text, + const gfx::Range& range, + size_t offset) { + for (auto& observer : observers_) + observer.DidChangeTextSelection(text, range, offset); +} +#endif + void WebContentsImpl::MoveCaret(const gfx::Point& extent) { RenderFrameHostImpl* focused_frame = GetFocusedFrame(); if (!focused_frame)
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index ccd1485..83f28751 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -729,6 +729,11 @@ const base::Optional<base::string16>& value) override; void MoveRangeSelectionExtent(const gfx::Point& extent) override; void SelectRange(const gfx::Point& base, const gfx::Point& extent) override; +#if defined(OS_MACOSX) + void DidChangeTextSelection(const base::string16& text, + const gfx::Range& range, + size_t offset) override; +#endif void MoveCaret(const gfx::Point& extent) override; void AdjustSelectionByCharacterOffset(int start_adjust, int end_adjust,
diff --git a/content/browser/web_package/signed_exchange_request_handler.cc b/content/browser/web_package/signed_exchange_request_handler.cc index 97e0b1e0..4bdb4e2b 100644 --- a/content/browser/web_package/signed_exchange_request_handler.cc +++ b/content/browser/web_package/signed_exchange_request_handler.cc
@@ -66,7 +66,8 @@ } if (signed_exchange_loader_->HasRedirectedToFallbackURL()) { signed_exchange_loader_ = nullptr; - std::move(callback).Run({}); + std::move(fallback_callback) + .Run(false /* reset_subresource_loader_params */); return; }
diff --git a/content/browser/webauth/scoped_virtual_authenticator_environment.cc b/content/browser/webauth/scoped_virtual_authenticator_environment.cc index 3f3d4a2d..482b3f0 100644 --- a/content/browser/webauth/scoped_virtual_authenticator_environment.cc +++ b/content/browser/webauth/scoped_virtual_authenticator_environment.cc
@@ -96,7 +96,7 @@ std::move(callback).Run(); } -std::unique_ptr<::device::FidoDiscovery> +std::unique_ptr<::device::FidoDeviceDiscovery> ScopedVirtualAuthenticatorEnvironment::CreateFidoDiscovery( device::FidoTransportProtocol transport, ::service_manager::Connector* connector) {
diff --git a/content/browser/webauth/scoped_virtual_authenticator_environment.h b/content/browser/webauth/scoped_virtual_authenticator_environment.h index 0c0bf6f..663738c 100644 --- a/content/browser/webauth/scoped_virtual_authenticator_environment.h +++ b/content/browser/webauth/scoped_virtual_authenticator_environment.h
@@ -13,7 +13,7 @@ #include "base/macros.h" #include "base/no_destructor.h" #include "content/common/content_export.h" -#include "device/fido/fido_discovery.h" +#include "device/fido/fido_device_discovery.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "third_party/blink/public/platform/modules/webauthn/virtual_authenticator.mojom.h" @@ -53,7 +53,7 @@ void ClearAuthenticators(ClearAuthenticatorsCallback callback) override; // ScopedFidoDiscoveryFactory: - std::unique_ptr<::device::FidoDiscovery> CreateFidoDiscovery( + std::unique_ptr<::device::FidoDeviceDiscovery> CreateFidoDiscovery( device::FidoTransportProtocol transport, ::service_manager::Connector* connector) override;
diff --git a/content/browser/webauth/virtual_discovery.cc b/content/browser/webauth/virtual_discovery.cc index 1f37ee8..82e022b4 100644 --- a/content/browser/webauth/virtual_discovery.cc +++ b/content/browser/webauth/virtual_discovery.cc
@@ -17,7 +17,7 @@ VirtualFidoDiscovery::VirtualFidoDiscovery( ScopedVirtualAuthenticatorEnvironment* environment, ::device::FidoTransportProtocol transport) - : FidoDiscovery(transport), environment_(environment) {} + : FidoDeviceDiscovery(transport), environment_(environment) {} VirtualFidoDiscovery::~VirtualFidoDiscovery() { environment_->OnDiscoveryDestroyed(this); @@ -28,7 +28,7 @@ // The real implementation would never notify the client's observer about // devices before the client calls Start(), mimic the same behavior. if (is_start_requested()) { - FidoDiscovery::AddDevice(std::move(device)); + FidoDeviceDiscovery::AddDevice(std::move(device)); } else { devices_pending_discovery_start_.push_back(std::move(device)); } @@ -36,12 +36,12 @@ bool VirtualFidoDiscovery::RemoveVirtualDevice(base::StringPiece device_id) { DCHECK(is_start_requested()); - return ::device::FidoDiscovery::RemoveDevice(device_id); + return ::device::FidoDeviceDiscovery::RemoveDevice(device_id); } void VirtualFidoDiscovery::StartInternal() { for (auto& device : devices_pending_discovery_start_) - FidoDiscovery::AddDevice(std::move(device)); + FidoDeviceDiscovery::AddDevice(std::move(device)); devices_pending_discovery_start_.clear(); base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/content/browser/webauth/virtual_discovery.h b/content/browser/webauth/virtual_discovery.h index 7c57b04..b4c14fc 100644 --- a/content/browser/webauth/virtual_discovery.h +++ b/content/browser/webauth/virtual_discovery.h
@@ -11,7 +11,7 @@ #include "base/macros.h" #include "base/strings/string_piece.h" #include "content/common/content_export.h" -#include "device/fido/fido_discovery.h" +#include "device/fido/fido_device_discovery.h" namespace device { class FidoDevice; @@ -21,9 +21,10 @@ class ScopedVirtualAuthenticatorEnvironment; -// A fully automated FidoDiscovery implementation, which is disconnected from -// the real world, and discovers VirtualFidoDevice instances. -class CONTENT_EXPORT VirtualFidoDiscovery : public ::device::FidoDiscovery { +// A fully automated FidoDeviceDiscovery implementation, which is disconnected +// from the real world, and discovers VirtualFidoDevice instances. +class CONTENT_EXPORT VirtualFidoDiscovery + : public ::device::FidoDeviceDiscovery { public: // The |environment| must outlive this instance. VirtualFidoDiscovery(ScopedVirtualAuthenticatorEnvironment* environment, @@ -36,7 +37,7 @@ bool RemoveVirtualDevice(base::StringPiece device_id); protected: - // FidoDiscovery: + // FidoDeviceDiscovery: void StartInternal() override; private:
diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc index 57bc30c..20c07c38 100644 --- a/content/browser/webauth/webauth_browsertest.cc +++ b/content/browser/webauth/webauth_browsertest.cc
@@ -590,7 +590,7 @@ // factory as one of the first steps. Here, the request should not have been // serviced at all, so the fake request should still be pending on the fake // factory. - auto hid_discovery = ::device::FidoDiscovery::Create( + auto hid_discovery = ::device::FidoDeviceDiscovery::Create( ::device::FidoTransportProtocol::kUsbHumanInterfaceDevice, nullptr); ASSERT_TRUE(!!hid_discovery);
diff --git a/content/browser/webui/web_ui_mojo_browsertest.cc b/content/browser/webui/web_ui_mojo_browsertest.cc index 3f403159..0425adab 100644 --- a/content/browser/webui/web_ui_mojo_browsertest.cc +++ b/content/browser/webui/web_ui_mojo_browsertest.cc
@@ -110,10 +110,23 @@ int bindings = BINDINGS_POLICY_MOJO_WEB_UI) : WebUIController(web_ui), run_loop_(run_loop) { web_ui->SetBindings(bindings); - WebUIDataSource* data_source = WebUIDataSource::Create("mojo-web-ui"); - data_source->SetRequestFilter(base::Bind(&GetResource)); - WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(), - data_source); + { + WebUIDataSource* data_source = WebUIDataSource::Create("mojo-web-ui"); + data_source->SetRequestFilter(base::BindRepeating(&GetResource)); + WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(), + data_source); + } + { + WebUIDataSource* data_source = WebUIDataSource::Create("dummy-web-ui"); + data_source->SetRequestFilter(base::BindRepeating( + [](const std::string& id, + const WebUIDataSource::GotDataCallback& callback) { + callback.Run(new base::RefCountedString); + return true; + })); + WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(), + data_source); + } } protected: @@ -246,9 +259,9 @@ TestWebUIControllerFactory* factory() { return &factory_; } void NavigateWithNewWebUI(const std::string& path) { - // Load an invalid URL first so that a new WebUI is set up when we load + // Load a dummy WebUI URL first so that a new WebUI is set up when we load // the URL we're actually interested in. - EXPECT_FALSE(NavigateToURL(shell(), GURL())); + EXPECT_TRUE(NavigateToURL(shell(), GURL("chrome://dummy-web-ui"))); constexpr char kChromeUIMojoWebUIOrigin[] = "chrome://mojo-web-ui/"; EXPECT_TRUE(NavigateToURL(shell(), GURL(kChromeUIMojoWebUIOrigin + path)));
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index 52ad94e..10a4266 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -315,7 +315,6 @@ "//media:shared_memory_support", "//media/base/ipc", "//media/capture", - "//media/capture/ipc", "//media/gpu:buildflags", "//media/gpu/ipc/client", "//media/gpu/ipc/common", @@ -349,6 +348,7 @@ "//ui/events/blink", "//ui/gfx", "//ui/gfx/geometry", + "//ui/gfx/geometry/mojo:struct_traits", "//ui/gfx/ipc", "//ui/gfx/ipc/color", "//ui/gfx/ipc/geometry",
diff --git a/content/common/render_frame_metadata.typemap b/content/common/render_frame_metadata.typemap index 3d7a39e..da6d300 100644 --- a/content/common/render_frame_metadata.typemap +++ b/content/common/render_frame_metadata.typemap
@@ -7,6 +7,7 @@ traits_headers = [ "//content/common/render_frame_metadata_struct_traits.h" ] deps = [ "//cc", + "//ui/gfx/geometry/mojo:struct_traits", ] sources = [ "//content/common/render_frame_metadata_struct_traits.cc",
diff --git a/content/common/service_worker/service_worker_loader_helpers.cc b/content/common/service_worker/service_worker_loader_helpers.cc index 4fece80..a05dbe61 100644 --- a/content/common/service_worker/service_worker_loader_helpers.cc +++ b/content/common/service_worker/service_worker_loader_helpers.cc
@@ -44,71 +44,6 @@ BlobCompleteCallback callback_; }; -// Sets |has_range_out| to true if |headers| specify a single range request, and -// |offset_out| and |length_out| to the range. If the range has an unbounded -// end, |length_out| is set to uint64_t's max value. Returns true on valid input -// (regardless of |has_range_out|), and false if there is more than one range or -// if the bounds overflow. -bool ExtractSinglePartHttpRange(const net::HttpRequestHeaders& headers, - bool* has_range_out, - uint64_t* offset_out, - uint64_t* length_out) { - std::string range_header; - *has_range_out = false; - if (!headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) - return true; - - std::vector<net::HttpByteRange> ranges; - if (!net::HttpUtil::ParseRangeHeader(range_header, &ranges)) - return true; - - // Multi-part (or invalid) ranges are not supported. - if (ranges.size() != 1) - return false; - - // Safely parse the single range to our more-sane output format. - *has_range_out = true; - const net::HttpByteRange& byte_range = ranges[0]; - - // The first byte must be non-negative. - if (byte_range.first_byte_position() < 0) - return false; - - // The last byte can be -1 to specify unbounded end. - if (byte_range.last_byte_position() == -1) { - // The range [0, -1] is the same as the entire range (no range specified). - if (byte_range.first_byte_position() == 0 && - byte_range.last_byte_position() == -1) { - *has_range_out = false; - return true; - } - - // Otherwise, return the range with unbounded end. - *length_out = std::numeric_limits<uint64_t>::max(); - return true; - } - - // The last byte must be non-negative. - if (byte_range.last_byte_position() < 0) - return false; - - uint64_t first_byte_position = - static_cast<uint64_t>(byte_range.first_byte_position()); - uint64_t last_byte_position = - static_cast<uint64_t>(byte_range.last_byte_position()); - - base::CheckedNumeric<uint64_t> length = last_byte_position; - length -= first_byte_position; - length += 1; - - if (!length.IsValid()) - return false; - - *offset_out = static_cast<uint64_t>(byte_range.first_byte_position()); - *length_out = length.ValueOrDie(); - return true; -} - } // namespace // static @@ -199,31 +134,18 @@ int ServiceWorkerLoaderHelpers::ReadBlobResponseBody( blink::mojom::BlobPtr* blob, uint64_t blob_size, - const net::HttpRequestHeaders& headers, base::OnceCallback<void(int)> on_blob_read_complete, mojo::ScopedDataPipeConsumerHandle* handle_out) { - bool byte_range_set = false; - uint64_t offset = 0; - uint64_t length = 0; - // We don't support multiple range requests in one single URL request, - // because we need to do multipart encoding here. - // TODO(falken): Support multipart byte range requests. - if (!ExtractSinglePartHttpRange(headers, &byte_range_set, &offset, &length)) - return net::ERR_REQUEST_RANGE_NOT_SATISFIABLE; - + // TODO(falken): Change to CreateDataPipe() and return an error if allocation + // failed. mojo::DataPipe data_pipe(blink::BlobUtils::GetDataPipeCapacity(blob_size)); blink::mojom::BlobReaderClientPtr blob_reader_client; mojo::MakeStrongBinding( std::make_unique<BlobCompleteCaller>(std::move(on_blob_read_complete)), mojo::MakeRequest(&blob_reader_client)); - if (byte_range_set) { - (*blob)->ReadRange(offset, length, std::move(data_pipe.producer_handle), - std::move(blob_reader_client)); - } else { - (*blob)->ReadAll(std::move(data_pipe.producer_handle), - std::move(blob_reader_client)); - } + (*blob)->ReadAll(std::move(data_pipe.producer_handle), + std::move(blob_reader_client)); *handle_out = std::move(data_pipe.consumer_handle); return net::OK; }
diff --git a/content/common/service_worker/service_worker_loader_helpers.h b/content/common/service_worker/service_worker_loader_helpers.h index 60da247c..5b037576 100644 --- a/content/common/service_worker/service_worker_loader_helpers.h +++ b/content/common/service_worker/service_worker_loader_helpers.h
@@ -40,14 +40,13 @@ const network::ResourceRequest& original_request, const network::ResourceResponseHead& response_head); - // Reads |blob| using the range in |headers| (if any), writing into - // |handle_out|. Calls |on_blob_read_complete| when done or if an error - // occurred. Returns a net error code if the inputs were invalid and reading - // couldn't start. In that case |on_blob_read_complete| isn't called. + // Reads |blob| into |handle_out|. Calls |on_blob_read_complete| when done or + // if an error occurred. Currently this always returns net::OK but + // the plan is to return an error if reading couldn't start, in + // which case |on_blob_read_complete| isn't called. static int ReadBlobResponseBody( blink::mojom::BlobPtr* blob, uint64_t blob_size, - const net::HttpRequestHeaders& headers, base::OnceCallback<void(int net_error)> on_blob_read_complete, mojo::ScopedDataPipeConsumerHandle* handle_out); };
diff --git a/content/common/view_messages.h b/content/common/view_messages.h index a7f73e6..e931fc0 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h
@@ -40,7 +40,6 @@ #include "media/base/audio_parameters.h" #include "media/base/channel_layout.h" #include "media/base/ipc/media_param_traits.h" -#include "media/capture/ipc/capture_param_traits.h" #include "net/base/network_change_notifier.h" #include "ppapi/buildflags/buildflags.h" #include "third_party/blink/public/common/manifest/web_display_mode.h"
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java index 31e7368..93e27a85 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
@@ -172,7 +172,6 @@ // The initial value is MODERATE since a newly created connection has moderate bindings. private @ChildProcessImportance int mEffectiveImportance = ChildProcessImportance.MODERATE; private boolean mVisible; - private boolean mIntersectsViewport; @CalledByNative private static FileDescriptorInfo makeFdInfo( @@ -468,14 +467,13 @@ } // Add first and remove second. - boolean wasAddedToBindingManager = mVisible && mIntersectsViewport; - boolean shouldAddToBindingManager = visible && intersectsViewport; - if (shouldAddToBindingManager && !wasAddedToBindingManager) { + if (visible && !mVisible) { BindingManager manager = getBindingManager(); if (mUseBindingManager && manager != null) { manager.addConnection(connection); } } + mVisible = visible; if (mEffectiveImportance != newEffectiveImportance) { switch (newEffectiveImportance) { @@ -521,8 +519,6 @@ } mEffectiveImportance = newEffectiveImportance; - mVisible = visible; - mIntersectsViewport = intersectsViewport; } @CalledByNative
diff --git a/content/public/browser/render_widget_host_view.h b/content/public/browser/render_widget_host_view.h index b691dd6..c662115 100644 --- a/content/public/browser/render_widget_host_view.h +++ b/content/public/browser/render_widget_host_view.h
@@ -141,6 +141,16 @@ // Returns the currently selected text. virtual base::string16 GetSelectedText() = 0; + // Returns part of the text on the page which includes the selected text plus + // possibly several characters before and after it. + virtual base::string16 GetSurroundingText() = 0; + + // Returns the range of the selection in the page. + virtual gfx::Range GetSelectedRange() = 0; + + // The offset of the surrounding text relative to the start of the total text. + virtual size_t GetOffsetForSurroundingText() = 0; + // This only returns non-null on platforms that implement touch // selection editing (TSE), currently Aura and (soon) Android. // TODO(wjmaclean): update this comment when OOPIF TSE is implemented on
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h index 3cb21f578..89ff658d 100644 --- a/content/public/browser/web_contents_observer.h +++ b/content/public/browser/web_contents_observer.h
@@ -25,6 +25,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/base/page_transition_types.h" #include "ui/base/window_open_disposition.h" +#include "ui/gfx/range/range.h" namespace blink { namespace mojom { @@ -454,6 +455,11 @@ // Invoked when theme color is changed to |theme_color|. virtual void DidChangeThemeColor(SkColor theme_color) {} + // Invoked when text selection is changed. + virtual void DidChangeTextSelection(const base::string16& text, + const gfx::Range& range, + size_t offset) {} + // Invoked when media is playing or paused. |id| is unique per player and per // RenderFrameHost. There may be multiple players within a RenderFrameHost // and subsequently within a WebContents. MediaStartedPlaying() will always
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 963de01..cc603a60 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -665,10 +665,6 @@ // entire life of the process. const base::Feature kMacV2Sandbox{"MacV2Sandbox", base::FEATURE_ENABLED_BY_DEFAULT}; -// -// Enables the suggested text touch bar for autocomplete in textfields. -const base::Feature kTextSuggestionsTouchBar{"TextSuggestionsTouchBar", - base::FEATURE_DISABLED_BY_DEFAULT}; #endif // defined(OS_MACOSX) enum class VideoCaptureServiceConfiguration {
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 95b77a7..874fc98f 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -161,7 +161,6 @@ CONTENT_EXPORT extern const base::Feature kDeviceMonitorMac; CONTENT_EXPORT extern const base::Feature kIOSurfaceCapturer; CONTENT_EXPORT extern const base::Feature kMacV2Sandbox; -CONTENT_EXPORT extern const base::Feature kTextSuggestionsTouchBar; #endif // defined(OS_MACOSX) // DON'T ADD RANDOM STUFF HERE. Put it in the main section above in
diff --git a/content/public/test/ppapi_test_utils.cc b/content/public/test/ppapi_test_utils.cc index f74bb7a7..35ef116 100644 --- a/content/public/test/ppapi_test_utils.cc +++ b/content/public/test/ppapi_test_utils.cc
@@ -11,6 +11,8 @@ #include "base/macros.h" #include "base/path_service.h" #include "build/build_config.h" +#include "content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h" +#include "content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h" #include "content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h" #include "content/public/common/content_constants.h" #include "content/public/common/content_switches.h" @@ -145,6 +147,14 @@ return RegisterPlugins(command_line, plugins); } +void SetPepperTCPNetworkContextForTesting( + network::mojom::NetworkContext* network_context) { + content::PepperTCPServerSocketMessageFilter::SetNetworkContextForTesting( + network_context); + content::PepperTCPSocketMessageFilter::SetNetworkContextForTesting( + network_context); +} + void SetPepperUDPSocketCallackForTesting( const CreateUDPSocketCallback* create_udp_socket_callback) { content::PepperUDPSocketMessageFilter::SetCreateUDPSocketCallbackForTesting(
diff --git a/content/public/test/ppapi_test_utils.h b/content/public/test/ppapi_test_utils.h index cbe1361..37bc819 100644 --- a/content/public/test/ppapi_test_utils.h +++ b/content/public/test/ppapi_test_utils.h
@@ -48,6 +48,12 @@ network::mojom::UDPSocketRequest socket_request, network::mojom::UDPSocketReceiverPtr socket_receiver)>; +// Sets a NetworkContext to be used by the Pepper TCP classes for testing. +// Passed in NetworkContext must remain valid until the method is called again +// with a nullptr, to clear the callback. +void SetPepperTCPNetworkContextForTesting( + network::mojom::NetworkContext* network_context); + // Sets callback to be invoked when creating a UDPSocket for use by pepper. // Passed in callback must remain valid until the method is called again with // a nullptr, to clear the callback.
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index e62bc40..8c69919 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -747,6 +747,7 @@ "//third_party/webrtc/pc:rtc_pc_base", "//third_party/webrtc/rtc_base:rtc_base", "//third_party/webrtc/rtc_base:rtc_task_queue", + "//third_party/webrtc/rtc_base:timeutils", # TODO(titovartem) remove dependency on WebRTC internals. "//third_party/webrtc/rtc_base/third_party/sigslot:sigslot",
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc index 57cd9e4..02f57f3 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.cc +++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -827,7 +827,7 @@ aria_rowcount); } - if (dst->role == ax::mojom::Role::kRow) { + if (ui::IsTableRowRole(dst->role)) { dst->AddIntAttribute(ax::mojom::IntAttribute::kTableRowIndex, src.RowIndex()); WebAXObject header = src.RowHeader(); @@ -836,35 +836,33 @@ header.AxID()); } - if (dst->role == ax::mojom::Role::kCell || - dst->role == ax::mojom::Role::kRowHeader || - dst->role == ax::mojom::Role::kColumnHeader || - dst->role == ax::mojom::Role::kRow) { - if (dst->role != ax::mojom::Role::kRow) { - dst->AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex, - src.CellColumnIndex()); - dst->AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnSpan, - src.CellColumnSpan()); - dst->AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex, - src.CellRowIndex()); - dst->AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowSpan, - src.CellRowSpan()); + if (ui::IsCellOrTableHeaderRole(dst->role)) { + dst->AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex, + src.CellColumnIndex()); + dst->AddIntAttribute(ax::mojom::IntAttribute::kTableCellColumnSpan, + src.CellColumnSpan()); + dst->AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex, + src.CellRowIndex()); + dst->AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowSpan, + src.CellRowSpan()); - int aria_colindex = src.AriaColumnIndex(); - if (aria_colindex) { - dst->AddIntAttribute(ax::mojom::IntAttribute::kAriaCellColumnIndex, - aria_colindex); - } + int aria_colindex = src.AriaColumnIndex(); + if (aria_colindex) { + dst->AddIntAttribute(ax::mojom::IntAttribute::kAriaCellColumnIndex, + aria_colindex); } + } + if (ui::IsCellOrTableHeaderRole(dst->role) || + ui::IsTableRowRole(dst->role)) { + // aria-rowindex is supported on cells, headers and rows. int aria_rowindex = src.AriaRowIndex(); if (aria_rowindex) dst->AddIntAttribute(ax::mojom::IntAttribute::kAriaCellRowIndex, aria_rowindex); } - if ((dst->role == ax::mojom::Role::kRowHeader || - dst->role == ax::mojom::Role::kColumnHeader) && + if (ui::IsTableHeaderRole(dst->role) && src.SortDirection() != ax::mojom::SortDirection::kNone) { dst->AddIntAttribute(ax::mojom::IntAttribute::kSortDirection, static_cast<int32_t>(src.SortDirection()));
diff --git a/content/renderer/gpu/layer_tree_view.cc b/content/renderer/gpu/layer_tree_view.cc index a4a31970..c843316 100644 --- a/content/renderer/gpu/layer_tree_view.cc +++ b/content/renderer/gpu/layer_tree_view.cc
@@ -612,15 +612,9 @@ delegate_->UpdateVisualState(); } -void LayerTreeView::ApplyViewportDeltas( - const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) { - delegate_->ApplyViewportDeltas(inner_delta, outer_delta, - elastic_overscroll_delta, page_scale, - top_controls_delta); +void LayerTreeView::ApplyViewportChanges( + const cc::ApplyViewportChangesArgs& args) { + delegate_->ApplyViewportChanges(args); } void LayerTreeView::RecordWheelAndTouchScrollingCount(
diff --git a/content/renderer/gpu/layer_tree_view.h b/content/renderer/gpu/layer_tree_view.h index 37d5783..daa3034 100644 --- a/content/renderer/gpu/layer_tree_view.h +++ b/content/renderer/gpu/layer_tree_view.h
@@ -181,11 +181,7 @@ void BeginMainFrameNotExpectedSoon() override; void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override; void UpdateLayerTreeHost() override; - void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) override; + void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override; void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel, bool has_scrolled_by_touch) override; void RequestNewLayerTreeFrameSink() override;
diff --git a/content/renderer/gpu/layer_tree_view_delegate.h b/content/renderer/gpu/layer_tree_view_delegate.h index 2ef7d29..68d11d6 100644 --- a/content/renderer/gpu/layer_tree_view_delegate.h +++ b/content/renderer/gpu/layer_tree_view_delegate.h
@@ -17,10 +17,6 @@ class SwapPromise; } // namespace cc -namespace gfx { -class Vector2dF; -} - namespace viz { class CopyOutputRequest; } @@ -36,12 +32,8 @@ // Report viewport related properties during a commit from the compositor // thread. - virtual void ApplyViewportDeltas( - const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) = 0; + virtual void ApplyViewportChanges( + const cc::ApplyViewportChangesArgs& args) = 0; // Record use count of wheel/touch sources for scrolling on the compositor // thread.
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index a24f837..88edfef 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -929,17 +929,11 @@ /////////////////////////////////////////////////////////////////////////////// // LayerTreeViewDelegate -void RenderWidget::ApplyViewportDeltas( - const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) { +void RenderWidget::ApplyViewportChanges( + const cc::ApplyViewportChangesArgs& args) { if (!GetWebWidget()) return; - GetWebWidget()->ApplyViewportDeltas(inner_delta, outer_delta, - elastic_overscroll_delta, page_scale, - top_controls_delta); + GetWebWidget()->ApplyViewportChanges(args); } void RenderWidget::RecordWheelAndTouchScrollingCount(
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index ff560a1..682cad6 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h
@@ -87,6 +87,7 @@ } // namespace blink namespace cc { +struct ApplyViewportChangesArgs; class SwapPromise; } @@ -255,11 +256,7 @@ bool Send(IPC::Message* msg) override; // LayerTreeViewDelegate - void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) override; + void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override; void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel, bool has_scrolled_by_touch) override; void BeginMainFrame(base::TimeTicks frame_time) override;
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc index 44cf532..1c0fae8b 100644 --- a/content/renderer/service_worker/service_worker_subresource_loader.cc +++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -586,7 +586,7 @@ UMA_HISTOGRAM_TIMES("ServiceWorker.SubresourceStartBlobReadingDelay", delay); return ServiceWorkerLoaderHelpers::ReadBlobResponseBody( - &body_as_blob_, body_as_blob_size_, resource_request_.headers, + &body_as_blob_, body_as_blob_size_, base::BindOnce(&ServiceWorkerSubresourceLoader::OnBlobReadingComplete, weak_factory_.GetWeakPtr()), body_pipe);
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc index 0caa164..3f6a0ba6 100644 --- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc +++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -11,6 +11,7 @@ #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "content/common/service_worker/service_worker_container.mojom.h" @@ -190,6 +191,7 @@ redirect_location_header_ = redirect_location_header; } + // Tells this controller to respond to fetch events with a blob response body. void RespondWithBlob(base::Optional<std::vector<uint8_t>> metadata, std::string body) { response_mode_ = ResponseMode::kBlob; @@ -201,6 +203,14 @@ mojo::MakeRequest(&blob_body_->blob)); } + // Tells this controller to respond to fetch events with a 206 partial + // response, returning a blob composed of the requested bytes of |body| + // according to the request headers. + void RespondWithBlobRange(std::string body) { + response_mode_ = ResponseMode::kBlobRange; + blob_range_body_ = body; + } + void ReadRequestBody(std::string* out_string) { ASSERT_TRUE(request_body_); std::vector<network::DataElement>* elements = @@ -270,6 +280,44 @@ blink::mojom::ServiceWorkerEventStatus::COMPLETED, base::TimeTicks()); break; + + case ResponseMode::kBlobRange: { + // Parse the Range header. + std::string range_header; + std::vector<net::HttpByteRange> ranges; + ASSERT_TRUE(params->request.headers.GetHeader( + net::HttpRequestHeaders::kRange, &range_header)); + ASSERT_TRUE(net::HttpUtil::ParseRangeHeader(range_header, &ranges)); + ASSERT_EQ(1u, ranges.size()); + ASSERT_TRUE(ranges[0].ComputeBounds(blob_range_body_.size())); + const net::HttpByteRange& range = ranges[0]; + + // Build a Blob composed of the requested bytes from |blob_range_body_|. + size_t start = static_cast<size_t>(range.first_byte_position()); + size_t end = static_cast<size_t>(range.last_byte_position()); + size_t size = end - start + 1; + std::string body = blob_range_body_.substr(start, size); + auto blob = blink::mojom::SerializedBlob::New(); + blob->uuid = "dummy-blob-uuid"; + blob->size = size; + mojo::MakeStrongBinding(std::make_unique<FakeBlob>(base::nullopt, body), + mojo::MakeRequest(&blob->blob)); + + // Respond with a 206 response. + auto response = OkResponse(std::move(blob)); + response->status_code = 206; + response->headers.emplace( + "Content-Range", base::StringPrintf("bytes %zu-%zu/%zu", start, end, + blob_range_body_.size())); + response_callback->OnResponse( + std::move(response), + blink::mojom::ServiceWorkerFetchEventTiming::New()); + std::move(callback).Run( + blink::mojom::ServiceWorkerEventStatus::COMPLETED, + base::TimeTicks::Now()); + break; + } + case ResponseMode::kFallbackResponse: response_callback->OnFallback( blink::mojom::ServiceWorkerFetchEventTiming::New()); @@ -320,6 +368,7 @@ kAbort, kStream, kBlob, + kBlobRange, kFallbackResponse, kErrorResponse, kRedirectResponse @@ -339,6 +388,9 @@ // For ResponseMode::kBlob. blink::mojom::SerializedBlobPtr blob_body_; + // For ResponseMode::kBlobRange. + std::string blob_range_body_; + // For ResponseMode::kRedirectResponse std::string redirect_location_header_; @@ -539,6 +591,30 @@ // cover this case in fetch-event.https.html. } + // Performs a range request using |range_header| and returns the resulting + // client after completion. + std::unique_ptr<network::TestURLLoaderClient> DoRangeRequest( + const std::string& range_header) { + network::mojom::URLLoaderFactoryPtr factory = + CreateSubresourceLoaderFactory(); + network::ResourceRequest request = + CreateRequest(GURL("https://www.example.com/big-file")); + request.headers.SetHeader("Range", range_header); + network::mojom::URLLoaderPtr loader; + std::unique_ptr<network::TestURLLoaderClient> client; + StartRequest(factory, request, &loader, &client); + client->RunUntilComplete(); + return client; + } + + std::string TakeResponseBody(network::TestURLLoaderClient* client) { + std::string body; + EXPECT_TRUE(client->response_body().is_valid()); + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &body)); + return body; + } + TestBrowserThreadBundle thread_bundle_; scoped_refptr<network::SharedURLLoaderFactory> loader_factory_; scoped_refptr<ControllerServiceWorkerConnector> connector_; @@ -1212,5 +1288,73 @@ RunFallbackWithRequestBodyTest(std::move(request_body), kData); } +// Test a range request that the service worker responds to with a 200 +// (non-ranged) response. The client should get the entire response as-is from +// the service worker. +TEST_F(ServiceWorkerSubresourceLoaderTest, RangeRequest_200Response) { + // Construct the Blob to respond with. + const std::string kResponseBody = "Here is sample text for the Blob."; + fake_controller_.RespondWithBlob(base::nullopt, kResponseBody); + + // Perform the request. + std::unique_ptr<network::TestURLLoaderClient> client = + DoRangeRequest("bytes=5-13"); + EXPECT_EQ(net::OK, client->completion_status().error_code); + + // Test the response. + const network::ResourceResponseHead& info = client->response_head(); + ExpectResponseInfo(info, *CreateResponseInfoFromServiceWorker()); + EXPECT_EQ(33, info.content_length); + EXPECT_FALSE(info.headers->HasHeader("Content-Range")); + EXPECT_EQ(kResponseBody, TakeResponseBody(client.get())); +} + +// Test a range request that the service worker responds to with a 206 ranged +// response. The client should get the partial response as-is from the service +// worker. +TEST_F(ServiceWorkerSubresourceLoaderTest, RangeRequest_206Response) { + // Tell the controller to respond with a 206 response. + const std::string kResponseBody = "Here is sample text for the Blob."; + fake_controller_.RespondWithBlobRange(kResponseBody); + + // Perform the request. + std::unique_ptr<network::TestURLLoaderClient> client = + DoRangeRequest("bytes=5-13"); + EXPECT_EQ(net::OK, client->completion_status().error_code); + + // Test the response. + const network::ResourceResponseHead& info = client->response_head(); + EXPECT_EQ(206, info.headers->response_code()); + std::string range; + ASSERT_TRUE(info.headers->GetNormalizedHeader("Content-Range", &range)); + EXPECT_EQ("bytes 5-13/33", range); + EXPECT_EQ(9, info.content_length); + EXPECT_EQ("is sample", TakeResponseBody(client.get())); +} + +// Test a range request that the service worker responds to with a 206 ranged +// response. The requested range has an unbounded end. The client should get the +// partial response as-is from the service worker. +TEST_F(ServiceWorkerSubresourceLoaderTest, + RangeRequest_UnboundedRight_206Response) { + // Tell the controller to respond with a 206 response. + const std::string kResponseBody = "Here is sample text for the Blob."; + fake_controller_.RespondWithBlobRange(kResponseBody); + + // Perform the request. + std::unique_ptr<network::TestURLLoaderClient> client = + DoRangeRequest("bytes=5-"); + EXPECT_EQ(net::OK, client->completion_status().error_code); + + // Test the response. + const network::ResourceResponseHead& info = client->response_head(); + EXPECT_EQ(206, info.headers->response_code()); + std::string range; + ASSERT_TRUE(info.headers->GetNormalizedHeader("Content-Range", &range)); + EXPECT_EQ("bytes 5-32/33", range); + EXPECT_EQ(28, info.content_length); + EXPECT_EQ("is sample text for the Blob.", TakeResponseBody(client.get())); +} + } // namespace service_worker_subresource_loader_unittest } // namespace content
diff --git a/content/shell/browser/layout_test/test_info_extractor.cc b/content/shell/browser/layout_test/test_info_extractor.cc index c425c9e..d8e9481 100644 --- a/content/shell/browser/layout_test/test_info_extractor.cc +++ b/content/shell/browser/layout_test/test_info_extractor.cc
@@ -13,6 +13,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" +#include "content/shell/common/layout_test/layout_test_switches.h" #include "net/base/filename_util.h" #include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" @@ -97,10 +98,18 @@ if (!base::PathExists(local_file)) { base::FilePath base_path; base::PathService::Get(base::DIR_SOURCE_ROOT, &base_path); - local_file = base_path.Append(FILE_PATH_LITERAL("third_party")) - .Append(FILE_PATH_LITERAL("WebKit")) - .Append(FILE_PATH_LITERAL("LayoutTests")) - .Append(local_file); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kTestsInBlink)) { + local_file = base_path.Append(FILE_PATH_LITERAL("third_party")) + .Append(FILE_PATH_LITERAL("blink")) + .Append(FILE_PATH_LITERAL("web_tests")) + .Append(local_file); + } else { + local_file = base_path.Append(FILE_PATH_LITERAL("third_party")) + .Append(FILE_PATH_LITERAL("WebKit")) + .Append(FILE_PATH_LITERAL("LayoutTests")) + .Append(local_file); + } } test_url = net::FilePathToFileURL(base::MakeAbsoluteFilePath(local_file)); }
diff --git a/content/shell/common/layout_test/layout_test_switches.cc b/content/shell/common/layout_test/layout_test_switches.cc index f1260fe..262a246 100644 --- a/content/shell/common/layout_test/layout_test_switches.cc +++ b/content/shell/common/layout_test/layout_test_switches.cc
@@ -56,6 +56,11 @@ // http://dev.chromium.org/blink/runtime-enabled-features. const char kStableReleaseMode[] = "stable-release-mode"; +// Test files are in //third_party/blink/web_tests, not in +// //third_party/WebKit/LayoutTests. +// TODO(tkent): Remove this flag after the move. +const char kTestsInBlink[] = "tests-in-blink"; + // Enable pixel dumps via "real" surface readbacks, instead of synchronously // compositing and reading back pixels. const char kEnableDisplayCompositorPixelDump[] =
diff --git a/content/shell/common/layout_test/layout_test_switches.h b/content/shell/common/layout_test/layout_test_switches.h index f0dedd32..ebbf47c 100644 --- a/content/shell/common/layout_test/layout_test_switches.h +++ b/content/shell/common/layout_test/layout_test_switches.h
@@ -30,6 +30,7 @@ extern const char kEncodeBinary[]; extern const char kRunWebTests[]; extern const char kStableReleaseMode[]; +extern const char kTestsInBlink[]; extern const char kEnableDisplayCompositorPixelDump[]; } // namespace switches
diff --git a/content/shell/renderer/layout_test/blink_test_helpers.cc b/content/shell/renderer/layout_test/blink_test_helpers.cc index 105b153..8f247ac4 100644 --- a/content/shell/renderer/layout_test/blink_test_helpers.cc +++ b/content/shell/renderer/layout_test/blink_test_helpers.cc
@@ -26,6 +26,24 @@ namespace { +base::FilePath GetWebTestsFilePath() { + static base::FilePath path; + if (path.empty()) { + base::FilePath root_path; + bool success = base::PathService::Get(base::DIR_SOURCE_ROOT, &root_path); + CHECK(success); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kTestsInBlink)) { + path = + root_path.Append(FILE_PATH_LITERAL("third_party/blink/web_tests/")); + } else { + path = root_path.Append( + FILE_PATH_LITERAL("third_party/WebKit/LayoutTests/")); + } + } + return path; +} + // Tests in csswg-test use absolute path links such as // <script src="/resources/testharness.js">. // Because we load the tests as local files, such links don't work. @@ -38,7 +56,8 @@ static constexpr base::StringPiece kFileScheme = "file:///"; if (!base::StartsWith(utf8_url, kFileScheme, base::CompareCase::SENSITIVE)) return WebURL(); - if (utf8_url.find("/LayoutTests/") != std::string::npos) + if (utf8_url.find("/LayoutTests/") != std::string::npos || + utf8_url.find("/web_tests/") != std::string::npos) return WebURL(); #if defined(OS_WIN) // +3 for a drive letter, :, and /. @@ -49,9 +68,7 @@ #else std::string path = utf8_url.substr(kFileScheme.size()); #endif - base::FilePath new_path = content::GetWebKitRootDirFilePath() - .Append(FILE_PATH_LITERAL("LayoutTests/")) - .AppendASCII(path); + base::FilePath new_path = GetWebTestsFilePath().AppendASCII(path); return WebURL(net::FilePathToFileURL(new_path)); } @@ -148,13 +165,6 @@ prefs->translate_service_available = true; } -base::FilePath GetWebKitRootDirFilePath() { - base::FilePath base_path; - bool success = base::PathService::Get(base::DIR_SOURCE_ROOT, &base_path); - CHECK(success); - return base_path.Append(FILE_PATH_LITERAL("third_party/WebKit")); -} - base::FilePath GetBuildDirectory() { base::FilePath result; bool success = base::PathService::Get(base::DIR_EXE, &result); @@ -193,14 +203,13 @@ return WebURL(GURL(new_url)); } + // TODO(tkent): Replace "tmp/LayoutTests" in tests with "tmp/web_tests". static constexpr base::StringPiece kPrefix = "file:///tmp/LayoutTests/"; if (!base::StartsWith(utf8_url, kPrefix, base::CompareCase::SENSITIVE)) return WebURL(GURL(utf8_url)); - base::FilePath replace_path = - GetWebKitRootDirFilePath().Append(FILE_PATH_LITERAL("LayoutTests/")); - std::string utf8_path = replace_path.AsUTF8Unsafe(); + std::string utf8_path = GetWebTestsFilePath().AsUTF8Unsafe(); std::string new_url = std::string("file://") + utf8_path + utf8_url.substr(kPrefix.size()); return WebURL(GURL(new_url));
diff --git a/content/shell/renderer/layout_test/blink_test_helpers.h b/content/shell/renderer/layout_test/blink_test_helpers.h index 9cbc647..e734eaaf 100644 --- a/content/shell/renderer/layout_test/blink_test_helpers.h +++ b/content/shell/renderer/layout_test/blink_test_helpers.h
@@ -28,9 +28,6 @@ // Applies settings that differ between layout tests and regular mode. void ApplyLayoutTestDefaultPreferences(WebPreferences* prefs); -// Returns the root of the Blink checkout. -base::FilePath GetWebKitRootDirFilePath(); - // The build directory of the Blink checkout. base::FilePath GetBuildDirectory();
diff --git a/content/shell/test_runner/test_common.cc b/content/shell/test_runner/test_common.cc index 0079ebd..520fcde 100644 --- a/content/shell/test_runner/test_common.cc +++ b/content/shell/test_runner/test_common.cc
@@ -19,6 +19,9 @@ const char layout_tests_pattern[] = "/LayoutTests/"; const std::string::size_type layout_tests_pattern_size = sizeof(layout_tests_pattern) - 1; +const char web_tests_pattern[] = "/web_tests/"; +const std::string::size_type web_tests_pattern_size = + sizeof(web_tests_pattern) - 1; const char file_url_pattern[] = "file:/"; const char file_test_prefix[] = "(file test):"; const char data_url_pattern[] = "data:"; @@ -43,6 +46,10 @@ ((pos = url.find(layout_tests_pattern)) != std::string::npos)) { // adjust file URLs to match upstream results. result.replace(0, pos + layout_tests_pattern_size, file_test_prefix); + } else if (!url.find(file_url_pattern) && + ((pos = url.find(web_tests_pattern)) != std::string::npos)) { + // adjust file URLs to match upstream results. + result.replace(0, pos + web_tests_pattern_size, file_test_prefix); } else if (!url.find(data_url_pattern)) { // URL-escape data URLs to match results upstream. std::string path = url.substr(data_url_pattern_size);
diff --git a/content/shell/test_runner/test_interfaces.cc b/content/shell/test_runner/test_interfaces.cc index e86a9a3..253ad08f 100644 --- a/content/shell/test_runner/test_interfaces.cc +++ b/content/shell/test_runner/test_interfaces.cc
@@ -98,8 +98,14 @@ bool initial_configuration) { std::string spec = GURL(test_url).spec(); size_t path_start = spec.rfind("LayoutTests/"); - if (path_start != std::string::npos) + if (path_start != std::string::npos) { spec = spec.substr(path_start); + } else { + path_start = spec.rfind("web_tests/"); + if (path_start != std::string::npos) + spec = spec.substr(path_start); + } + bool is_devtools_test = spec.find("/devtools/") != std::string::npos; if (is_devtools_test) { test_runner_->SetDumpConsoleMessages(false);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 0b1ea0a..8d1779f 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1930,6 +1930,7 @@ "//third_party/webrtc/modules/video_coding:video_codec_interface", "//third_party/webrtc/pc:libjingle_peerconnection", "//third_party/webrtc/rtc_base:rtc_base", + "//third_party/webrtc/rtc_base:timeutils", "//third_party/webrtc/stats:rtc_stats_test_utils", "//third_party/webrtc_overrides", "//third_party/webrtc_overrides:init_webrtc", @@ -1945,6 +1946,7 @@ "//ui/events/blink", "//ui/gfx:test_support", "//ui/gfx/geometry", + "//ui/gfx/geometry/mojo:struct_traits", "//ui/gfx/ipc", "//ui/gfx/ipc/skia", "//ui/gl",
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py index aa545ca7..82caed7 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -726,6 +726,8 @@ ['android', 'nvidia'], bug=830901) self.Flaky('conformance/extensions/oes-texture-half-float-with-video.html', ['android', 'nvidia'], bug=891456) + self.Flaky('conformance/extensions/oes-texture-float-with-video.html', + ['android', 'nvidia'], bug=891456) self.Flaky('conformance/textures/image_bitmap_from_video/' + 'tex-2d-rgb-rgb-unsigned_short_5_6_5.html', ['android', 'nvidia'], bug=891456)
diff --git a/content/test/stub_layer_tree_view_delegate.h b/content/test/stub_layer_tree_view_delegate.h index a2545a6..52b0e4f 100644 --- a/content/test/stub_layer_tree_view_delegate.h +++ b/content/test/stub_layer_tree_view_delegate.h
@@ -7,16 +7,16 @@ #include "content/renderer/gpu/layer_tree_view_delegate.h" +namespace cc { +struct ApplyViewportChangesArgs; +} + namespace content { class StubLayerTreeViewDelegate : public LayerTreeViewDelegate { public: // LayerTreeViewDelegate implementation. - void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) override {} + void ApplyViewportChanges(const cc::ApplyViewportChangesArgs&) override {} void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel, bool has_scrolled_by_touch) override {} void BeginMainFrame(base::TimeTicks frame_time) override {}
diff --git a/device/BUILD.gn b/device/BUILD.gn index 3bcd647..28d6cc8 100644 --- a/device/BUILD.gn +++ b/device/BUILD.gn
@@ -82,7 +82,7 @@ "fido/ctap_request_unittest.cc", "fido/ctap_response_unittest.cc", "fido/fake_fido_discovery_unittest.cc", - "fido/fido_discovery_unittest.cc", + "fido/fido_device_discovery_unittest.cc", "fido/fido_parsing_utils_unittest.cc", "fido/fido_request_handler_unittest.cc", "fido/get_assertion_handler_unittest.cc",
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn index bf97afc..b1cbe99 100644 --- a/device/fido/BUILD.gn +++ b/device/fido/BUILD.gn
@@ -71,8 +71,8 @@ "fido_device.h", "fido_device_authenticator.cc", "fido_device_authenticator.h", - "fido_discovery.cc", - "fido_discovery.h", + "fido_device_discovery.cc", + "fido_device_discovery.h", "fido_discovery_base.cc", "fido_discovery_base.h", "fido_parsing_utils.cc",
diff --git a/device/fido/ble/fido_ble_discovery.cc b/device/fido/ble/fido_ble_discovery.cc index 073585e..4a6ade3 100644 --- a/device/fido/ble/fido_ble_discovery.cc +++ b/device/fido/ble/fido_ble_discovery.cc
@@ -15,6 +15,7 @@ #include "device/fido/ble/fido_ble_device.h" #include "device/fido/ble/fido_ble_uuids.h" #include "device/fido/fido_authenticator.h" +#include "device/fido/fido_device_authenticator.h" namespace device { @@ -74,8 +75,8 @@ } const auto device_id = FidoBleDevice::GetId(device->GetAddress()); - auto* fido_device = GetDevice(device_id); - if (!fido_device) { + auto* authenticator = GetAuthenticator(device_id); + if (!authenticator) { VLOG(2) << "Discovered U2F service on existing BLE device: " << device->GetAddress(); AddDevice(std::make_unique<FidoBleDevice>(adapter, device->GetAddress())); @@ -87,7 +88,7 @@ // and BluetoothAdapter::DeviceRemoved() is invoked instead of returning back // to regular "non-pairing" mode. As so, we only notify observer when // |fido_device| goes into pairing mode. - if (observer() && fido_device->IsInPairingMode()) + if (observer() && authenticator->device()->IsInPairingMode()) observer()->AuthenticatorPairingModeChanged(this, device_id); } @@ -113,14 +114,14 @@ const std::string& old_address) { auto previous_device_id = FidoBleDevice::GetId(old_address); auto new_device_id = FidoBleDevice::GetId(device->GetAddress()); - auto it = devices_.find(previous_device_id); - if (it == devices_.end()) + auto it = authenticators_.find(previous_device_id); + if (it == authenticators_.end()) return; VLOG(2) << "Discovered FIDO BLE device address change from old address : " << old_address << " to new address : " << device->GetAddress(); - devices_.emplace(new_device_id, std::move(it->second)); - devices_.erase(it); + authenticators_.emplace(new_device_id, std::move(it->second)); + authenticators_.erase(it); if (observer()) { observer()->AuthenticatorIdChanged(this, previous_device_id,
diff --git a/device/fido/ble/fido_ble_discovery_base.cc b/device/fido/ble/fido_ble_discovery_base.cc index 6ef5475..240513c7 100644 --- a/device/fido/ble/fido_ble_discovery_base.cc +++ b/device/fido/ble/fido_ble_discovery_base.cc
@@ -20,7 +20,7 @@ namespace device { FidoBleDiscoveryBase::FidoBleDiscoveryBase(FidoTransportProtocol transport) - : FidoDiscovery(transport), weak_factory_(this) {} + : FidoDeviceDiscovery(transport), weak_factory_(this) {} FidoBleDiscoveryBase::~FidoBleDiscoveryBase() { if (adapter_)
diff --git a/device/fido/ble/fido_ble_discovery_base.h b/device/fido/ble/fido_ble_discovery_base.h index 3a1f64c..c8885d7 100644 --- a/device/fido/ble/fido_ble_discovery_base.h +++ b/device/fido/ble/fido_ble_discovery_base.h
@@ -13,14 +13,14 @@ #include "base/memory/weak_ptr.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_uuid.h" -#include "device/fido/fido_discovery.h" +#include "device/fido/fido_device_discovery.h" namespace device { class BluetoothDiscoverySession; class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscoveryBase - : public FidoDiscovery, + : public FidoDeviceDiscovery, public BluetoothAdapter::Observer { public: explicit FidoBleDiscoveryBase(FidoTransportProtocol transport); @@ -44,7 +44,7 @@ private: void OnGetAdapter(scoped_refptr<BluetoothAdapter> adapter); - // FidoDiscovery: + // FidoDeviceDiscovery: void StartInternal() override; scoped_refptr<BluetoothAdapter> adapter_;
diff --git a/device/fido/ble/fido_ble_discovery_unittest.cc b/device/fido/ble/fido_ble_discovery_unittest.cc index 2fa673e4..48533cc 100644 --- a/device/fido/ble/fido_ble_discovery_unittest.cc +++ b/device/fido/ble/fido_ble_discovery_unittest.cc
@@ -16,7 +16,7 @@ #include "device/bluetooth/test/mock_bluetooth_device.h" #include "device/fido/ble/fido_ble_device.h" #include "device/fido/ble/fido_ble_uuids.h" -#include "device/fido/fido_authenticator.h" +#include "device/fido/fido_device_authenticator.h" #include "device/fido/mock_fido_discovery_observer.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -192,7 +192,7 @@ discovery.Start(); run_loop.Run(); - EXPECT_THAT(discovery.GetDevices(), ::testing::IsEmpty()); + EXPECT_THAT(discovery.GetAuthenticatorsForTesting(), ::testing::IsEmpty()); } { @@ -209,10 +209,10 @@ run_loop.Run(); - const auto devices = discovery.GetDevices(); - ASSERT_THAT(devices, ::testing::SizeIs(1u)); + const auto authenticators = discovery.GetAuthenticatorsForTesting(); + ASSERT_THAT(authenticators, ::testing::SizeIs(1u)); EXPECT_EQ(FidoBleDevice::GetId(BluetoothTestBase::kTestDeviceAddress1), - devices[0]->GetId()); + authenticators[0]->GetId()); } } @@ -288,8 +288,8 @@ mock_adapter->NotifyDeviceChanged(mock_device.get()); - EXPECT_EQ(1u, discovery.GetDevices().size()); - EXPECT_TRUE(discovery.GetDevice(kAuthenticatorChangedId)); + EXPECT_EQ(1u, discovery.GetAuthenticatorsForTesting().size()); + EXPECT_TRUE(discovery.GetAuthenticatorForTesting(kAuthenticatorChangedId)); } TEST_F(BluetoothTest, DiscoveryNotifiesObserverWhenDeviceInPairingMode) {
diff --git a/device/fido/fake_fido_discovery.cc b/device/fido/fake_fido_discovery.cc index c0c9283..7e49f9a4 100644 --- a/device/fido/fake_fido_discovery.cc +++ b/device/fido/fake_fido_discovery.cc
@@ -20,7 +20,7 @@ FakeFidoDiscovery::FakeFidoDiscovery(FidoTransportProtocol transport, StartMode mode) - : FidoDiscovery(transport), mode_(mode) {} + : FidoDeviceDiscovery(transport), mode_(mode) {} FakeFidoDiscovery::~FakeFidoDiscovery() = default; void FakeFidoDiscovery::WaitForCallToStart() { @@ -80,7 +80,7 @@ return next_cable_discovery_.get(); } -std::unique_ptr<FidoDiscovery> +std::unique_ptr<FidoDeviceDiscovery> ScopedFakeFidoDiscoveryFactory::CreateFidoDiscovery( FidoTransportProtocol transport, ::service_manager::Connector* connector) {
diff --git a/device/fido/fake_fido_discovery.h b/device/fido/fake_fido_discovery.h index 15f55bd..57a65b7 100644 --- a/device/fido/fake_fido_discovery.h +++ b/device/fido/fake_fido_discovery.h
@@ -11,7 +11,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/run_loop.h" -#include "device/fido/fido_discovery.h" +#include "device/fido/fido_device_discovery.h" #include "device/fido/fido_transport_protocol.h" namespace service_manager { @@ -32,10 +32,11 @@ // auto* fake_ble_discovery = factory.ForgeNextBleDiscovery(); // // // Run the production code that will eventually call: -// //// FidoDiscovery::Create(FidoTransportProtocol::kUsbHumanInterfaceDevice) -// //// hid_instance->Start(); -// //// FidoDiscovery::Create(FidoTransportProtocol::kBluetoothLowEnergy) -// //// ble_instance->Start(); +// // FidoDeviceDiscovery::Create( +// // FidoTransportProtocol::kUsbHumanInterfaceDevice) +// // hid_instance->Start(); +// // FidoDeviceDiscovery::Create(FidoTransportProtocol::kBluetoothLowEnergy) +// // ble_instance->Start(); // // // Wait, i.e. spin the message loop until the fake discoveries are started. // fake_hid_discovery->WaitForCallToStart(); @@ -54,7 +55,7 @@ // // Destroy the production instance to eventually stop the discovery. // // hid_instance.reset(); // -class FakeFidoDiscovery : public FidoDiscovery, +class FakeFidoDiscovery : public FidoDeviceDiscovery, public base::SupportsWeakPtr<FakeFidoDiscovery> { public: enum class StartMode { @@ -80,11 +81,11 @@ // Tests are to directly call Add/RemoveDevice to simulate adding/removing // devices. Observers are automatically notified. - using FidoDiscovery::AddDevice; - using FidoDiscovery::RemoveDevice; + using FidoDeviceDiscovery::AddDevice; + using FidoDeviceDiscovery::RemoveDevice; private: - // FidoDiscovery: + // FidoDeviceDiscovery: void StartInternal() override; const StartMode mode_; @@ -93,8 +94,8 @@ DISALLOW_COPY_AND_ASSIGN(FakeFidoDiscovery); }; -// Overrides FidoDiscovery::Create to construct FakeFidoDiscoveries while this -// instance is in scope. +// Overrides FidoDeviceDiscovery::Create to construct FakeFidoDiscoveries while +// this instance is in scope. class ScopedFakeFidoDiscoveryFactory : public ::device::internal::ScopedFidoDiscoveryFactory { public: @@ -104,11 +105,11 @@ ~ScopedFakeFidoDiscoveryFactory() override; // Constructs a fake discovery to be returned from the next call to - // FidoDiscovery::Create. Returns a raw pointer to the fake so that tests can - // set it up according to taste. + // FidoDeviceDiscovery::Create. Returns a raw pointer to the fake so that + // tests can set it up according to taste. // // It is an error not to call the relevant method prior to a call to - // FidoDiscovery::Create with the respective transport. + // FidoDeviceDiscovery::Create with the respective transport. FakeFidoDiscovery* ForgeNextHidDiscovery(StartMode mode = StartMode::kManual); FakeFidoDiscovery* ForgeNextNfcDiscovery(StartMode mode = StartMode::kManual); FakeFidoDiscovery* ForgeNextBleDiscovery(StartMode mode = StartMode::kManual); @@ -116,7 +117,7 @@ StartMode mode = StartMode::kManual); protected: - std::unique_ptr<FidoDiscovery> CreateFidoDiscovery( + std::unique_ptr<FidoDeviceDiscovery> CreateFidoDiscovery( FidoTransportProtocol transport, ::service_manager::Connector* connector) override;
diff --git a/device/fido/fake_fido_discovery_unittest.cc b/device/fido/fake_fido_discovery_unittest.cc index 8e38849..407d710 100644 --- a/device/fido/fake_fido_discovery_unittest.cc +++ b/device/fido/fake_fido_discovery_unittest.cc
@@ -150,7 +150,7 @@ auto* injected_fake_discovery = factory.ForgeNextHidDiscovery(); ASSERT_EQ(FidoTransportProtocol::kUsbHumanInterfaceDevice, injected_fake_discovery->transport()); - auto produced_discovery = FidoDiscovery::Create( + auto produced_discovery = FidoDeviceDiscovery::Create( FidoTransportProtocol::kUsbHumanInterfaceDevice, nullptr); EXPECT_TRUE(produced_discovery); EXPECT_EQ(injected_fake_discovery, produced_discovery.get()); @@ -164,14 +164,14 @@ auto* injected_fake_discovery_1 = factory.ForgeNextBleDiscovery(); ASSERT_EQ(FidoTransportProtocol::kBluetoothLowEnergy, injected_fake_discovery_1->transport()); - auto produced_discovery_1 = FidoDiscovery::Create( + auto produced_discovery_1 = FidoDeviceDiscovery::Create( FidoTransportProtocol::kBluetoothLowEnergy, nullptr); EXPECT_EQ(injected_fake_discovery_1, produced_discovery_1.get()); auto* injected_fake_discovery_2 = factory.ForgeNextBleDiscovery(); ASSERT_EQ(FidoTransportProtocol::kBluetoothLowEnergy, injected_fake_discovery_2->transport()); - auto produced_discovery_2 = FidoDiscovery::Create( + auto produced_discovery_2 = FidoDeviceDiscovery::Create( FidoTransportProtocol::kBluetoothLowEnergy, nullptr); EXPECT_EQ(injected_fake_discovery_2, produced_discovery_2.get()); }
diff --git a/device/fido/fido_device.h b/device/fido/fido_device.h index 9e7678f..5a8bb38 100644 --- a/device/fido/fido_device.h +++ b/device/fido/fido_device.h
@@ -27,7 +27,7 @@ // Devices are instantiated with an unknown protocol version. Users should call // |DiscoverSupportedProtocolAndDeviceInfo| to determine a device's // capabilities and initialize the instance accordingly. Instances returned by -// |FidoDiscovery| are already fully initialized. +// |FidoDeviceDiscovery| are not fully initialized. class COMPONENT_EXPORT(DEVICE_FIDO) FidoDevice { public: using WinkCallback = base::OnceClosure;
diff --git a/device/fido/fido_device_authenticator.cc b/device/fido/fido_device_authenticator.cc index d7c68533..f011e9e 100644 --- a/device/fido/fido_device_authenticator.cc +++ b/device/fido/fido_device_authenticator.cc
@@ -18,8 +18,9 @@ namespace device { -FidoDeviceAuthenticator::FidoDeviceAuthenticator(FidoDevice* device) - : device_(device), weak_factory_(this) {} +FidoDeviceAuthenticator::FidoDeviceAuthenticator( + std::unique_ptr<FidoDevice> device) + : device_(std::move(device)), weak_factory_(this) {} FidoDeviceAuthenticator::~FidoDeviceAuthenticator() = default; void FidoDeviceAuthenticator::InitializeAuthenticator( @@ -37,15 +38,15 @@ << "InitializeAuthenticator() must be called first."; // TODO(martinkr): Change FidoTasks to take all request parameters by const // reference, so we can avoid copying these from the RequestHandler. - task_ = std::make_unique<MakeCredentialTask>(device_, std::move(request), - std::move(callback)); + task_ = std::make_unique<MakeCredentialTask>( + device_.get(), std::move(request), std::move(callback)); } void FidoDeviceAuthenticator::GetAssertion(CtapGetAssertionRequest request, GetAssertionCallback callback) { DCHECK(device_->SupportedProtocolIsInitialized()) << "InitializeAuthenticator() must be called first."; - task_ = std::make_unique<GetAssertionTask>(device_, std::move(request), + task_ = std::make_unique<GetAssertionTask>(device_.get(), std::move(request), std::move(callback)); }
diff --git a/device/fido/fido_device_authenticator.h b/device/fido/fido_device_authenticator.h index 84a7b44..06738e4 100644 --- a/device/fido/fido_device_authenticator.h +++ b/device/fido/fido_device_authenticator.h
@@ -29,7 +29,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceAuthenticator : public FidoAuthenticator { public: - FidoDeviceAuthenticator(FidoDevice* device); + FidoDeviceAuthenticator(std::unique_ptr<FidoDevice> device); ~FidoDeviceAuthenticator() override; // FidoAuthenticator: @@ -46,7 +46,7 @@ bool IsInPairingMode() const override; base::WeakPtr<FidoAuthenticator> GetWeakPtr() override; - FidoDevice* GetDeviceForTesting() { return device_; } + FidoDevice* device() { return device_.get(); } protected: void OnCtapMakeCredentialResponseReceived( @@ -56,11 +56,10 @@ GetAssertionCallback callback, base::Optional<std::vector<uint8_t>> response_data); - FidoDevice* device() { return device_; } void SetTaskForTesting(std::unique_ptr<FidoTask> task); private: - FidoDevice* const device_; + const std::unique_ptr<FidoDevice> device_; std::unique_ptr<FidoTask> task_; base::WeakPtrFactory<FidoDeviceAuthenticator> weak_factory_;
diff --git a/device/fido/fido_device_discovery.cc b/device/fido/fido_device_discovery.cc new file mode 100644 index 0000000..fe7fbe1a --- /dev/null +++ b/device/fido/fido_device_discovery.cc
@@ -0,0 +1,223 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/fido/fido_device_discovery.h" + +#include <utility> + +#include "base/bind.h" +#include "build/build_config.h" +#include "device/fido/ble/fido_ble_discovery.h" +#include "device/fido/cable/fido_cable_discovery.h" +#include "device/fido/fido_authenticator.h" +#include "device/fido/fido_device.h" +#include "device/fido/fido_device_authenticator.h" + +// HID is not supported on Android. +#if !defined(OS_ANDROID) +#include "device/fido/hid/fido_hid_discovery.h" +#endif // !defined(OS_ANDROID) + +namespace device { + +namespace { + +std::unique_ptr<FidoDeviceDiscovery> CreateFidoDiscoveryImpl( + FidoTransportProtocol transport, + service_manager::Connector* connector) { + switch (transport) { + case FidoTransportProtocol::kUsbHumanInterfaceDevice: +#if !defined(OS_ANDROID) + DCHECK(connector); + return std::make_unique<FidoHidDiscovery>(connector); +#else + NOTREACHED() << "USB HID not supported on Android."; + return nullptr; +#endif // !defined(OS_ANDROID) + case FidoTransportProtocol::kBluetoothLowEnergy: + return std::make_unique<FidoBleDiscovery>(); + case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy: + NOTREACHED() << "Cable discovery is constructed using the dedicated " + "factory method."; + return nullptr; + case FidoTransportProtocol::kNearFieldCommunication: + // TODO(https://crbug.com/825949): Add NFC support. + return nullptr; + case FidoTransportProtocol::kInternal: + NOTREACHED() << "Internal authenticators should be handled separately."; + return nullptr; + } + NOTREACHED() << "Unhandled transport type"; + return nullptr; +} + +std::unique_ptr<FidoDeviceDiscovery> CreateCableDiscoveryImpl( + std::vector<CableDiscoveryData> cable_data) { + return std::make_unique<FidoCableDiscovery>(std::move(cable_data)); +} + +} // namespace + +FidoDeviceDiscovery::Observer::~Observer() = default; + +// static +FidoDeviceDiscovery::FactoryFuncPtr FidoDeviceDiscovery::g_factory_func_ = + &CreateFidoDiscoveryImpl; + +// static +FidoDeviceDiscovery::CableFactoryFuncPtr + FidoDeviceDiscovery::g_cable_factory_func_ = &CreateCableDiscoveryImpl; + +// static +std::unique_ptr<FidoDeviceDiscovery> FidoDeviceDiscovery::Create( + FidoTransportProtocol transport, + service_manager::Connector* connector) { + return (*g_factory_func_)(transport, connector); +} + +// static +std::unique_ptr<FidoDeviceDiscovery> FidoDeviceDiscovery::CreateCable( + std::vector<CableDiscoveryData> cable_data) { + return (*g_cable_factory_func_)(std::move(cable_data)); +} + +FidoDeviceDiscovery::FidoDeviceDiscovery(FidoTransportProtocol transport) + : FidoDiscoveryBase(transport), weak_factory_(this) {} + +FidoDeviceDiscovery::~FidoDeviceDiscovery() = default; + +void FidoDeviceDiscovery::Start() { + DCHECK_EQ(state_, State::kIdle); + state_ = State::kStarting; + // TODO(hongjunchoi): Fix so that NotifiyStarted() is never called + // synchronously after StartInternal(). + // See: https://crbug.com/823686 + StartInternal(); +} + +void FidoDeviceDiscovery::NotifyDiscoveryStarted(bool success) { + DCHECK_EQ(state_, State::kStarting); + if (success) + state_ = State::kRunning; + if (!observer()) + return; + observer()->DiscoveryStarted(this, success); +} + +void FidoDeviceDiscovery::NotifyAuthenticatorAdded( + FidoAuthenticator* authenticator) { + DCHECK_NE(state_, State::kIdle); + if (!observer()) + return; + observer()->AuthenticatorAdded(this, authenticator); +} + +void FidoDeviceDiscovery::NotifyAuthenticatorRemoved( + FidoAuthenticator* authenticator) { + DCHECK_NE(state_, State::kIdle); + if (!observer()) + return; + observer()->AuthenticatorRemoved(this, authenticator); +} + +std::vector<FidoDeviceAuthenticator*> +FidoDeviceDiscovery::GetAuthenticatorsForTesting() { + std::vector<FidoDeviceAuthenticator*> authenticators; + authenticators.reserve(authenticators_.size()); + for (const auto& authenticator : authenticators_) + authenticators.push_back(authenticator.second.get()); + return authenticators; +} + +std::vector<const FidoDeviceAuthenticator*> +FidoDeviceDiscovery::GetAuthenticatorsForTesting() const { + std::vector<const FidoDeviceAuthenticator*> authenticators; + authenticators.reserve(authenticators_.size()); + for (const auto& authenticator : authenticators_) + authenticators.push_back(authenticator.second.get()); + return authenticators; +} + +FidoDeviceAuthenticator* FidoDeviceDiscovery::GetAuthenticatorForTesting( + base::StringPiece authenticator_id) { + return GetAuthenticator(authenticator_id); +} + +FidoDeviceAuthenticator* FidoDeviceDiscovery::GetAuthenticator( + base::StringPiece authenticator_id) { + auto found = authenticators_.find(authenticator_id); + return found != authenticators_.end() ? found->second.get() : nullptr; +} + +bool FidoDeviceDiscovery::AddDevice(std::unique_ptr<FidoDevice> device) { + auto authenticator = + std::make_unique<FidoDeviceAuthenticator>(std::move(device)); + const auto result = + authenticators_.emplace(authenticator->GetId(), std::move(authenticator)); + if (!result.second) { + return false; // Duplicate device id. + } + + NotifyAuthenticatorAdded(result.first->second.get()); + return true; +} + +bool FidoDeviceDiscovery::RemoveDevice(base::StringPiece device_id) { + auto found = authenticators_.find(device_id); + if (found == authenticators_.end()) + return false; + + auto authenticator = std::move(found->second); + authenticators_.erase(found); + NotifyAuthenticatorRemoved(authenticator.get()); + return true; +} + +// ScopedFidoDiscoveryFactory ------------------------------------------------- + +namespace internal { + +ScopedFidoDiscoveryFactory::ScopedFidoDiscoveryFactory() { + DCHECK(!g_current_factory); + g_current_factory = this; + original_factory_func_ = + std::exchange(FidoDeviceDiscovery::g_factory_func_, + &ForwardCreateFidoDiscoveryToCurrentFactory); + original_cable_factory_func_ = + std::exchange(FidoDeviceDiscovery::g_cable_factory_func_, + &ForwardCreateCableDiscoveryToCurrentFactory); +} + +ScopedFidoDiscoveryFactory::~ScopedFidoDiscoveryFactory() { + g_current_factory = nullptr; + FidoDeviceDiscovery::g_factory_func_ = original_factory_func_; + FidoDeviceDiscovery::g_cable_factory_func_ = original_cable_factory_func_; +} + +// static +std::unique_ptr<FidoDeviceDiscovery> +ScopedFidoDiscoveryFactory::ForwardCreateFidoDiscoveryToCurrentFactory( + FidoTransportProtocol transport, + ::service_manager::Connector* connector) { + DCHECK(g_current_factory); + return g_current_factory->CreateFidoDiscovery(transport, connector); +} + +// static +std::unique_ptr<FidoDeviceDiscovery> +ScopedFidoDiscoveryFactory::ForwardCreateCableDiscoveryToCurrentFactory( + std::vector<CableDiscoveryData> cable_data) { + DCHECK(g_current_factory); + g_current_factory->set_last_cable_data(std::move(cable_data)); + return g_current_factory->CreateFidoDiscovery( + FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy, + nullptr /* connector */); +} + +// static +ScopedFidoDiscoveryFactory* ScopedFidoDiscoveryFactory::g_current_factory = + nullptr; + +} // namespace internal +} // namespace device
diff --git a/device/fido/fido_discovery.h b/device/fido/fido_device_discovery.h similarity index 71% rename from device/fido/fido_discovery.h rename to device/fido/fido_device_discovery.h index e8d67c7..d5b844fac 100644 --- a/device/fido/fido_discovery.h +++ b/device/fido/fido_device_discovery.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 DEVICE_FIDO_FIDO_DISCOVERY_H_ -#define DEVICE_FIDO_FIDO_DISCOVERY_H_ +#ifndef DEVICE_FIDO_FIDO_DEVICE_DISCOVERY_H_ +#define DEVICE_FIDO_FIDO_DEVICE_DISCOVERY_H_ #include <functional> #include <map> @@ -28,12 +28,14 @@ namespace device { class FidoDevice; +class FidoDeviceAuthenticator; namespace internal { class ScopedFidoDiscoveryFactory; } -class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery : public FidoDiscoveryBase { +class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceDiscovery + : public FidoDiscoveryBase { public: enum class State { kIdle, @@ -47,29 +49,28 @@ // // FidoTransportProtocol::kUsbHumanInterfaceDevice requires specifying a valid // |connector| on Desktop, and is not valid on Android. - static std::unique_ptr<FidoDiscovery> Create( + static std::unique_ptr<FidoDeviceDiscovery> Create( FidoTransportProtocol transport, ::service_manager::Connector* connector); - static std::unique_ptr<FidoDiscovery> CreateCable( + static std::unique_ptr<FidoDeviceDiscovery> CreateCable( std::vector<CableDiscoveryData> cable_data); - ~FidoDiscovery() override; + ~FidoDeviceDiscovery() override; bool is_start_requested() const { return state_ != State::kIdle; } bool is_running() const { return state_ == State::kRunning; } - std::vector<FidoDevice*> GetDevices(); - std::vector<const FidoDevice*> GetDevices() const; - - // TODO(martinkr): Rename to GetDeviceForTesting. - FidoDevice* GetDevice(base::StringPiece device_id); - const FidoDevice* GetDevice(base::StringPiece device_id) const; + std::vector<FidoDeviceAuthenticator*> GetAuthenticatorsForTesting(); + std::vector<const FidoDeviceAuthenticator*> GetAuthenticatorsForTesting() + const; + FidoDeviceAuthenticator* GetAuthenticatorForTesting( + base::StringPiece authenticator_id); // FidoDiscoveryBase: void Start() override; protected: - FidoDiscovery(FidoTransportProtocol transport); + FidoDeviceDiscovery(FidoTransportProtocol transport); void NotifyDiscoveryStarted(bool success); void NotifyAuthenticatorAdded(FidoAuthenticator* authenticator); @@ -78,6 +79,8 @@ bool AddDevice(std::unique_ptr<FidoDevice> device); bool RemoveDevice(base::StringPiece device_id); + FidoDeviceAuthenticator* GetAuthenticator(base::StringPiece authenticator_id); + // Subclasses should implement this to actually start the discovery when it is // requested. // @@ -85,11 +88,10 @@ // the discovery is s tarted. virtual void StartInternal() = 0; - std::map<std::string, - std::pair<std::unique_ptr<FidoAuthenticator>, - std::unique_ptr<FidoDevice>>, - std::less<>> - devices_; + // Map of ID to authenticator. It is a guarantee to subclasses that the ID of + // the authenticator equals the ID of the device. + std::map<std::string, std::unique_ptr<FidoDeviceAuthenticator>, std::less<>> + authenticators_; private: friend class internal::ScopedFidoDiscoveryFactory; @@ -101,14 +103,14 @@ static CableFactoryFuncPtr g_cable_factory_func_; State state_ = State::kIdle; - base::WeakPtrFactory<FidoDiscovery> weak_factory_; + base::WeakPtrFactory<FidoDeviceDiscovery> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(FidoDiscovery); + DISALLOW_COPY_AND_ASSIGN(FidoDeviceDiscovery); }; namespace internal { -// Base class for a scoped override of FidoDiscovery::Create, used in unit +// Base class for a scoped override of FidoDeviceDiscovery::Create, used in unit // tests, layout tests, and when running with the Web Authn Testing API enabled. // // While there is a subclass instance in scope, calls to the factory method will @@ -129,24 +131,24 @@ last_cable_data_ = std::move(cable_data); } - virtual std::unique_ptr<FidoDiscovery> CreateFidoDiscovery( + virtual std::unique_ptr<FidoDeviceDiscovery> CreateFidoDiscovery( FidoTransportProtocol transport, ::service_manager::Connector* connector) = 0; private: - static std::unique_ptr<FidoDiscovery> + static std::unique_ptr<FidoDeviceDiscovery> ForwardCreateFidoDiscoveryToCurrentFactory( FidoTransportProtocol transport, ::service_manager::Connector* connector); - static std::unique_ptr<FidoDiscovery> + static std::unique_ptr<FidoDeviceDiscovery> ForwardCreateCableDiscoveryToCurrentFactory( std::vector<CableDiscoveryData> cable_data); static ScopedFidoDiscoveryFactory* g_current_factory; - FidoDiscovery::FactoryFuncPtr original_factory_func_; - FidoDiscovery::CableFactoryFuncPtr original_cable_factory_func_; + FidoDeviceDiscovery::FactoryFuncPtr original_factory_func_; + FidoDeviceDiscovery::CableFactoryFuncPtr original_cable_factory_func_; std::vector<CableDiscoveryData> last_cable_data_; DISALLOW_COPY_AND_ASSIGN(ScopedFidoDiscoveryFactory); @@ -155,4 +157,4 @@ } // namespace internal } // namespace device -#endif // DEVICE_FIDO_FIDO_DISCOVERY_H_ +#endif // DEVICE_FIDO_FIDO_DEVICE_DISCOVERY_H_
diff --git a/device/fido/fido_discovery_unittest.cc b/device/fido/fido_device_discovery_unittest.cc similarity index 82% rename from device/fido/fido_discovery_unittest.cc rename to device/fido/fido_device_discovery_unittest.cc index 4ebf0ab1..9e984c94 100644 --- a/device/fido/fido_discovery_unittest.cc +++ b/device/fido/fido_device_discovery_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "device/fido/fido_discovery.h" +#include "device/fido/fido_device_discovery.h" #include <utility> @@ -27,18 +27,18 @@ using ::testing::SaveArg; using ::testing::UnorderedElementsAre; -// A minimal implementation of FidoDiscovery that is no longer abstract. -class ConcreteFidoDiscovery : public FidoDiscovery { +// A minimal implementation of FidoDeviceDiscovery that is no longer abstract. +class ConcreteFidoDiscovery : public FidoDeviceDiscovery { public: explicit ConcreteFidoDiscovery(FidoTransportProtocol transport) - : FidoDiscovery(transport) {} + : FidoDeviceDiscovery(transport) {} ~ConcreteFidoDiscovery() override = default; MOCK_METHOD0(StartInternal, void()); - using FidoDiscovery::AddDevice; - using FidoDiscovery::NotifyDiscoveryStarted; - using FidoDiscovery::RemoveDevice; + using FidoDeviceDiscovery::AddDevice; + using FidoDeviceDiscovery::NotifyDiscoveryStarted; + using FidoDeviceDiscovery::RemoveDevice; private: DISALLOW_COPY_AND_ASSIGN(ConcreteFidoDiscovery); @@ -112,8 +112,8 @@ EXPECT_CALL(*device0, GetId()).WillRepeatedly(Return("device0")); EXPECT_TRUE(discovery.AddDevice(std::move(device0))); EXPECT_EQ("device0", authenticator0->GetId()); - EXPECT_EQ(device0_raw, static_cast<FidoDeviceAuthenticator*>(authenticator0) - ->GetDeviceForTesting()); + EXPECT_EQ(device0_raw, + static_cast<FidoDeviceAuthenticator*>(authenticator0)->device()); device0_done.Run(); ::testing::Mock::VerifyAndClearExpectations(&observer); @@ -129,8 +129,8 @@ EXPECT_CALL(*device1, GetId()).WillRepeatedly(Return("device1")); EXPECT_TRUE(discovery.AddDevice(std::move(device1))); EXPECT_EQ("device1", authenticator1->GetId()); - EXPECT_EQ(device1_raw, static_cast<FidoDeviceAuthenticator*>(authenticator1) - ->GetDeviceForTesting()); + EXPECT_EQ(device1_raw, + static_cast<FidoDeviceAuthenticator*>(authenticator1)->device()); device1_done.Run(); ::testing::Mock::VerifyAndClearExpectations(&observer); @@ -141,16 +141,14 @@ EXPECT_FALSE(discovery.AddDevice(std::move(device1_dup))); ::testing::Mock::VerifyAndClearExpectations(&observer); - EXPECT_EQ(device0_raw, discovery.GetDevice("device0")); - EXPECT_EQ(device1_raw, discovery.GetDevice("device1")); - EXPECT_THAT(discovery.GetDevices(), - UnorderedElementsAre(device0_raw, device1_raw)); + EXPECT_EQ(authenticator0, discovery.GetAuthenticatorForTesting("device0")); + EXPECT_EQ(authenticator1, discovery.GetAuthenticatorForTesting("device1")); + EXPECT_THAT(discovery.GetAuthenticatorsForTesting(), + UnorderedElementsAre(authenticator0, authenticator1)); - const FidoDiscovery& const_discovery = discovery; - EXPECT_EQ(device0_raw, const_discovery.GetDevice("device0")); - EXPECT_EQ(device1_raw, const_discovery.GetDevice("device1")); - EXPECT_THAT(const_discovery.GetDevices(), - UnorderedElementsAre(device0_raw, device1_raw)); + const FidoDeviceDiscovery& const_discovery = discovery; + EXPECT_THAT(const_discovery.GetAuthenticatorsForTesting(), + UnorderedElementsAre(authenticator0, authenticator1)); // Trying to remove a non-present device should fail. EXPECT_CALL(observer, AuthenticatorRemoved(_, _)).Times(0);
diff --git a/device/fido/fido_discovery.cc b/device/fido/fido_discovery.cc deleted file mode 100644 index ccedf32..0000000 --- a/device/fido/fido_discovery.cc +++ /dev/null
@@ -1,220 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "device/fido/fido_discovery.h" - -#include <utility> - -#include "base/bind.h" -#include "build/build_config.h" -#include "device/fido/ble/fido_ble_discovery.h" -#include "device/fido/cable/fido_cable_discovery.h" -#include "device/fido/fido_authenticator.h" -#include "device/fido/fido_device.h" -#include "device/fido/fido_device_authenticator.h" - -// HID is not supported on Android. -#if !defined(OS_ANDROID) -#include "device/fido/hid/fido_hid_discovery.h" -#endif // !defined(OS_ANDROID) - -namespace device { - -namespace { - -std::unique_ptr<FidoDiscovery> CreateFidoDiscoveryImpl( - FidoTransportProtocol transport, - service_manager::Connector* connector) { - switch (transport) { - case FidoTransportProtocol::kUsbHumanInterfaceDevice: -#if !defined(OS_ANDROID) - DCHECK(connector); - return std::make_unique<FidoHidDiscovery>(connector); -#else - NOTREACHED() << "USB HID not supported on Android."; - return nullptr; -#endif // !defined(OS_ANDROID) - case FidoTransportProtocol::kBluetoothLowEnergy: - return std::make_unique<FidoBleDiscovery>(); - case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy: - NOTREACHED() << "Cable discovery is constructed using the dedicated " - "factory method."; - return nullptr; - case FidoTransportProtocol::kNearFieldCommunication: - // TODO(https://crbug.com/825949): Add NFC support. - return nullptr; - case FidoTransportProtocol::kInternal: - NOTREACHED() << "Internal authenticators should be handled separately."; - return nullptr; - } - NOTREACHED() << "Unhandled transport type"; - return nullptr; -} - -std::unique_ptr<FidoDiscovery> CreateCableDiscoveryImpl( - std::vector<CableDiscoveryData> cable_data) { - return std::make_unique<FidoCableDiscovery>(std::move(cable_data)); -} - -} // namespace - -FidoDiscovery::Observer::~Observer() = default; - -// static -FidoDiscovery::FactoryFuncPtr FidoDiscovery::g_factory_func_ = - &CreateFidoDiscoveryImpl; - -// static -FidoDiscovery::CableFactoryFuncPtr FidoDiscovery::g_cable_factory_func_ = - &CreateCableDiscoveryImpl; - -// static -std::unique_ptr<FidoDiscovery> FidoDiscovery::Create( - FidoTransportProtocol transport, - service_manager::Connector* connector) { - return (*g_factory_func_)(transport, connector); -} - -// static -std::unique_ptr<FidoDiscovery> FidoDiscovery::CreateCable( - std::vector<CableDiscoveryData> cable_data) { - return (*g_cable_factory_func_)(std::move(cable_data)); -} - -FidoDiscovery::FidoDiscovery(FidoTransportProtocol transport) - : FidoDiscoveryBase(transport), weak_factory_(this) {} - -FidoDiscovery::~FidoDiscovery() = default; - -void FidoDiscovery::Start() { - DCHECK_EQ(state_, State::kIdle); - state_ = State::kStarting; - // TODO(hongjunchoi): Fix so that NotifiyStarted() is never called - // synchronously after StartInternal(). - // See: https://crbug.com/823686 - StartInternal(); -} - -void FidoDiscovery::NotifyDiscoveryStarted(bool success) { - DCHECK_EQ(state_, State::kStarting); - if (success) - state_ = State::kRunning; - if (!observer()) - return; - observer()->DiscoveryStarted(this, success); -} - -void FidoDiscovery::NotifyAuthenticatorAdded(FidoAuthenticator* authenticator) { - DCHECK_NE(state_, State::kIdle); - if (!observer()) - return; - observer()->AuthenticatorAdded(this, authenticator); -} - -void FidoDiscovery::NotifyAuthenticatorRemoved( - FidoAuthenticator* authenticator) { - DCHECK_NE(state_, State::kIdle); - if (!observer()) - return; - observer()->AuthenticatorRemoved(this, authenticator); -} - -std::vector<FidoDevice*> FidoDiscovery::GetDevices() { - std::vector<FidoDevice*> devices; - devices.reserve(devices_.size()); - for (const auto& device : devices_) - devices.push_back(device.second.second.get()); - return devices; -} - -std::vector<const FidoDevice*> FidoDiscovery::GetDevices() const { - std::vector<const FidoDevice*> devices; - devices.reserve(devices_.size()); - for (const auto& device : devices_) - devices.push_back(device.second.second.get()); - return devices; -} - -FidoDevice* FidoDiscovery::GetDevice(base::StringPiece device_id) { - return const_cast<FidoDevice*>( - static_cast<const FidoDiscovery*>(this)->GetDevice(device_id)); -} - -const FidoDevice* FidoDiscovery::GetDevice(base::StringPiece device_id) const { - auto found = devices_.find(device_id); - return found != devices_.end() ? found->second.second.get() : nullptr; -} - -bool FidoDiscovery::AddDevice(std::unique_ptr<FidoDevice> device) { - std::string device_id = device->GetId(); - auto authenticator = std::make_unique<FidoDeviceAuthenticator>(device.get()); - const auto result = devices_.emplace( - std::move(device_id), - std::make_pair(std::move(authenticator), std::move(device))); - if (!result.second) { - return false; // Duplicate device id. - } - - NotifyAuthenticatorAdded(result.first->second.first.get()); - return true; -} - -bool FidoDiscovery::RemoveDevice(base::StringPiece device_id) { - auto found = devices_.find(device_id); - if (found == devices_.end()) - return false; - - auto authenticator_device_pair = std::move(found->second); - devices_.erase(found); - NotifyAuthenticatorRemoved(authenticator_device_pair.first.get()); - return true; -} - -// ScopedFidoDiscoveryFactory ------------------------------------------------- - -namespace internal { - -ScopedFidoDiscoveryFactory::ScopedFidoDiscoveryFactory() { - DCHECK(!g_current_factory); - g_current_factory = this; - original_factory_func_ = - std::exchange(FidoDiscovery::g_factory_func_, - &ForwardCreateFidoDiscoveryToCurrentFactory); - original_cable_factory_func_ = - std::exchange(FidoDiscovery::g_cable_factory_func_, - &ForwardCreateCableDiscoveryToCurrentFactory); -} - -ScopedFidoDiscoveryFactory::~ScopedFidoDiscoveryFactory() { - g_current_factory = nullptr; - FidoDiscovery::g_factory_func_ = original_factory_func_; - FidoDiscovery::g_cable_factory_func_ = original_cable_factory_func_; -} - -// static -std::unique_ptr<FidoDiscovery> -ScopedFidoDiscoveryFactory::ForwardCreateFidoDiscoveryToCurrentFactory( - FidoTransportProtocol transport, - ::service_manager::Connector* connector) { - DCHECK(g_current_factory); - return g_current_factory->CreateFidoDiscovery(transport, connector); -} - -// static -std::unique_ptr<FidoDiscovery> -ScopedFidoDiscoveryFactory::ForwardCreateCableDiscoveryToCurrentFactory( - std::vector<CableDiscoveryData> cable_data) { - DCHECK(g_current_factory); - g_current_factory->set_last_cable_data(std::move(cable_data)); - return g_current_factory->CreateFidoDiscovery( - FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy, - nullptr /* connector */); -} - -// static -ScopedFidoDiscoveryFactory* ScopedFidoDiscoveryFactory::g_current_factory = - nullptr; - -} // namespace internal -} // namespace device
diff --git a/device/fido/fido_request_handler_base.cc b/device/fido/fido_request_handler_base.cc index 54138b6..6164f84 100644 --- a/device/fido/fido_request_handler_base.cc +++ b/device/fido/fido_request_handler_base.cc
@@ -84,7 +84,7 @@ continue; } - auto discovery = FidoDiscovery::Create(transport, connector); + auto discovery = FidoDeviceDiscovery::Create(transport, connector); if (discovery == nullptr) { // This can occur in tests when a ScopedVirtualU2fDevice is in effect and // HID transports are not configured.
diff --git a/device/fido/fido_request_handler_base.h b/device/fido/fido_request_handler_base.h index 550d36d..76a301c 100644 --- a/device/fido/fido_request_handler_base.h +++ b/device/fido/fido_request_handler_base.h
@@ -20,7 +20,7 @@ #include "base/memory/weak_ptr.h" #include "base/strings/string_piece_forward.h" #include "device/fido/fido_device_authenticator.h" -#include "device/fido/fido_discovery.h" +#include "device/fido/fido_device_discovery.h" #include "device/fido/fido_transport_protocol.h" namespace service_manager { @@ -223,8 +223,8 @@ TransportAvailabilityInfo transport_availability_info_; base::RepeatingClosure notify_observer_callback_; std::unique_ptr<BleAdapterManager> bluetooth_adapter_manager_; - // TODO(martinkr): Inject platform authenticators through FidoDiscovery and - // hold ownership there. + // TODO(martinkr): Inject platform authenticators through a new + // FidoDiscoveryBase specialization and hold ownership there. std::unique_ptr<FidoAuthenticator> platform_authenticator_; base::WeakPtrFactory<FidoRequestHandlerBase> weak_factory_;
diff --git a/device/fido/fido_request_handler_unittest.cc b/device/fido/fido_request_handler_unittest.cc index 117d54a..aea5531 100644 --- a/device/fido/fido_request_handler_unittest.cc +++ b/device/fido/fido_request_handler_unittest.cc
@@ -163,8 +163,8 @@ class FakeFidoAuthenticator : public FidoDeviceAuthenticator { public: - explicit FakeFidoAuthenticator(FidoDevice* device) - : FidoDeviceAuthenticator(device) {} + explicit FakeFidoAuthenticator(std::unique_ptr<FidoDevice> device) + : FidoDeviceAuthenticator(std::move(device)) {} void RunFakeTask(FakeTaskCallback callback) { SetTaskForTesting( @@ -506,7 +506,8 @@ device->ExpectRequestAndRespondWith(std::vector<uint8_t>(), CreateFakeSuccessDeviceResponse()); device->SetDeviceTransport(FidoTransportProtocol::kInternal); - auto authenticator = std::make_unique<FakeFidoAuthenticator>(device.get()); + auto authenticator = + std::make_unique<FakeFidoAuthenticator>(std::move(device)); TestTransportAvailabilityObserver observer; auto request_handler = std::make_unique<FakeFidoRequestHandler>( @@ -541,7 +542,8 @@ device->ExpectRequestAndRespondWith(std::vector<uint8_t>(), CreateFakeSuccessDeviceResponse()); device->SetDeviceTransport(FidoTransportProtocol::kInternal); - auto authenticator = std::make_unique<FakeFidoAuthenticator>(device.get()); + auto authenticator = + std::make_unique<FakeFidoAuthenticator>(std::move(device)); TestTransportAvailabilityObserver observer; auto request_handler = std::make_unique<FakeFidoRequestHandler>(
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc index e7626578..c31d827 100644 --- a/device/fido/get_assertion_handler_unittest.cc +++ b/device/fido/get_assertion_handler_unittest.cc
@@ -147,7 +147,7 @@ } void set_mock_platform_device(std::unique_ptr<MockFidoDevice> device) { - mock_platform_device_ = std::move(device); + pending_mock_platform_device_ = std::move(device); } void set_supported_transports( @@ -157,10 +157,11 @@ protected: base::Optional<PlatformAuthenticatorInfo> CreatePlatformAuthenticator() { - if (!mock_platform_device_) + if (!pending_mock_platform_device_) return base::nullopt; return PlatformAuthenticatorInfo( - std::make_unique<FidoDeviceAuthenticator>(mock_platform_device_.get()), + std::make_unique<FidoDeviceAuthenticator>( + std::move(pending_mock_platform_device_)), false /* has_recognized_mac_touch_id_credential_available */); } @@ -173,7 +174,7 @@ test::FakeFidoDiscovery* cable_discovery_; test::FakeFidoDiscovery* nfc_discovery_; scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> mock_adapter_; - std::unique_ptr<MockFidoDevice> mock_platform_device_; + std::unique_ptr<MockFidoDevice> pending_mock_platform_device_; TestGetAssertionRequestCallback get_assertion_cb_; base::flat_set<FidoTransportProtocol> supported_transports_ = GetAllTransportProtocols();
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc index 1e7888a..9d71e48 100644 --- a/device/fido/get_assertion_request_handler.cc +++ b/device/fido/get_assertion_request_handler.cc
@@ -175,7 +175,8 @@ transport_availability_info().available_transports, FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy)) { DCHECK(request_.cable_extension()); - auto discovery = FidoDiscovery::CreateCable(*request_.cable_extension()); + auto discovery = + FidoDeviceDiscovery::CreateCable(*request_.cable_extension()); discovery->set_observer(this); discoveries().push_back(std::move(discovery)); }
diff --git a/device/fido/hid/fido_hid_discovery.cc b/device/fido/hid/fido_hid_discovery.cc index b1eb519..92b908ec 100644 --- a/device/fido/hid/fido_hid_discovery.cc +++ b/device/fido/hid/fido_hid_discovery.cc
@@ -14,7 +14,7 @@ namespace device { FidoHidDiscovery::FidoHidDiscovery(::service_manager::Connector* connector) - : FidoDiscovery(FidoTransportProtocol::kUsbHumanInterfaceDevice), + : FidoDeviceDiscovery(FidoTransportProtocol::kUsbHumanInterfaceDevice), connector_(connector), binding_(this), weak_factory_(this) {
diff --git a/device/fido/hid/fido_hid_discovery.h b/device/fido/hid/fido_hid_discovery.h index c6a5e78..f2aae1a 100644 --- a/device/fido/hid/fido_hid_discovery.h +++ b/device/fido/hid/fido_hid_discovery.h
@@ -11,7 +11,7 @@ #include "base/component_export.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "device/fido/fido_discovery.h" +#include "device/fido/fido_device_discovery.h" #include "mojo/public/cpp/bindings/associated_binding.h" #include "services/device/public/cpp/hid/hid_device_filter.h" #include "services/device/public/mojom/hid.mojom.h" @@ -26,14 +26,14 @@ // servicification is unblocked, we'll move U2F back to //service/device/. // Then it will talk to HID via C++ as part of servicifying U2F. class COMPONENT_EXPORT(DEVICE_FIDO) FidoHidDiscovery - : public FidoDiscovery, + : public FidoDeviceDiscovery, device::mojom::HidManagerClient { public: explicit FidoHidDiscovery(::service_manager::Connector* connector); ~FidoHidDiscovery() override; private: - // FidoDiscovery: + // FidoDeviceDiscovery: void StartInternal() override; // device::mojom::HidManagerClient implementation:
diff --git a/device/fido/make_credential_handler_unittest.cc b/device/fido/make_credential_handler_unittest.cc index 8b47f1b..9fb5b67c 100644 --- a/device/fido/make_credential_handler_unittest.cc +++ b/device/fido/make_credential_handler_unittest.cc
@@ -120,7 +120,7 @@ TestMakeCredentialRequestCallback& callback() { return cb_; } void set_mock_platform_device(std::unique_ptr<MockFidoDevice> device) { - mock_platform_device_ = std::move(device); + pending_mock_platform_device_ = std::move(device); } void set_supported_transports( @@ -130,10 +130,11 @@ protected: base::Optional<PlatformAuthenticatorInfo> CreatePlatformAuthenticator() { - if (!mock_platform_device_) + if (!pending_mock_platform_device_) return base::nullopt; return PlatformAuthenticatorInfo( - std::make_unique<FidoDeviceAuthenticator>(mock_platform_device_.get()), + std::make_unique<FidoDeviceAuthenticator>( + std::move(pending_mock_platform_device_)), false /* has_recognized_mac_touch_id_credential_available */); } @@ -145,7 +146,7 @@ test::FakeFidoDiscovery* ble_discovery_; test::FakeFidoDiscovery* nfc_discovery_; scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> mock_adapter_; - std::unique_ptr<MockFidoDevice> mock_platform_device_; + std::unique_ptr<MockFidoDevice> pending_mock_platform_device_; TestMakeCredentialRequestCallback cb_; base::flat_set<FidoTransportProtocol> supported_transports_ = GetAllTransportProtocols();
diff --git a/device/fido/mock_fido_device.h b/device/fido/mock_fido_device.h index 2337341..83dfaca 100644 --- a/device/fido/mock_fido_device.h +++ b/device/fido/mock_fido_device.h
@@ -27,19 +27,19 @@ public: // MakeU2f returns a fully initialized U2F device. This represents the state // after |DiscoverSupportedProtocolAndDeviceInfo| has been called by the - // FidoDiscovery. + // FidoDeviceDiscovery. static std::unique_ptr<MockFidoDevice> MakeU2f(); // MakeCtap returns a fully initialized CTAP device. This represents the // state after |DiscoverSupportedProtocolAndDeviceInfo| has been called by - // the FidoDiscovery. + // the FidoDeviceDiscovery. static std::unique_ptr<MockFidoDevice> MakeCtap( base::Optional<AuthenticatorGetInfoResponse> device_info = base::nullopt); // MakeU2fWithDeviceInfoExpectation returns a uninitialized U2F device - // suitable for injecting into a FidoDiscovery, which will determine its + // suitable for injecting into a FidoDeviceDiscovery, which will determine its // protocol version by invoking |DiscoverSupportedProtocolAndDeviceInfo|. static std::unique_ptr<MockFidoDevice> MakeU2fWithGetInfoExpectation(); // MakeCtapWithDeviceInfoExpectation returns a uninitialized CTAP device - // suitable for injecting into a FidoDiscovery, which will determine its + // suitable for injecting into a FidoDeviceDiscovery, which will determine its // protocol version by invoking |DiscoverSupportedProtocolAndDeviceInfo|. If a // response is supplied, the mock will use that to reply; otherwise it will // use |test_data::kTestAuthenticatorGetInfoResponse|.
diff --git a/device/fido/mock_fido_discovery_observer.h b/device/fido/mock_fido_discovery_observer.h index 21bd96ad..883b20a 100644 --- a/device/fido/mock_fido_discovery_observer.h +++ b/device/fido/mock_fido_discovery_observer.h
@@ -9,7 +9,7 @@ #include "base/component_export.h" #include "base/macros.h" -#include "device/fido/fido_discovery.h" +#include "device/fido/fido_device_discovery.h" #include "testing/gmock/include/gmock/gmock.h" namespace device {
diff --git a/device/fido/scoped_virtual_fido_device.cc b/device/fido/scoped_virtual_fido_device.cc index b0807e3..7bfd960d 100644 --- a/device/fido/scoped_virtual_fido_device.cc +++ b/device/fido/scoped_virtual_fido_device.cc
@@ -18,15 +18,15 @@ namespace device { namespace test { -// A FidoDiscovery that always vends a single |VirtualFidoDevice|. +// A FidoDeviceDiscovery that always vends a single |VirtualFidoDevice|. class VirtualFidoDeviceDiscovery - : public FidoDiscovery, + : public FidoDeviceDiscovery, public base::SupportsWeakPtr<VirtualFidoDeviceDiscovery> { public: explicit VirtualFidoDeviceDiscovery( scoped_refptr<VirtualFidoDevice::State> state, ProtocolVersion supported_protocol) - : FidoDiscovery(FidoTransportProtocol::kUsbHumanInterfaceDevice), + : FidoDeviceDiscovery(FidoTransportProtocol::kUsbHumanInterfaceDevice), state_(std::move(state)), supported_protocol_(supported_protocol) {} ~VirtualFidoDeviceDiscovery() override = default; @@ -65,7 +65,8 @@ return state_.get(); } -std::unique_ptr<FidoDiscovery> ScopedVirtualFidoDevice::CreateFidoDiscovery( +std::unique_ptr<FidoDeviceDiscovery> +ScopedVirtualFidoDevice::CreateFidoDiscovery( FidoTransportProtocol transport, ::service_manager::Connector* connector) { if (transport != FidoTransportProtocol::kUsbHumanInterfaceDevice) {
diff --git a/device/fido/scoped_virtual_fido_device.h b/device/fido/scoped_virtual_fido_device.h index 4c63e52..88bc6b4e 100644 --- a/device/fido/scoped_virtual_fido_device.h +++ b/device/fido/scoped_virtual_fido_device.h
@@ -9,7 +9,7 @@ #include "base/macros.h" #include "device/fido/fido_constants.h" -#include "device/fido/fido_discovery.h" +#include "device/fido/fido_device_discovery.h" #include "device/fido/virtual_fido_device.h" namespace device { @@ -28,7 +28,7 @@ VirtualFidoDevice::State* mutable_state(); protected: - std::unique_ptr<FidoDiscovery> CreateFidoDiscovery( + std::unique_ptr<FidoDeviceDiscovery> CreateFidoDiscovery( FidoTransportProtocol transport, ::service_manager::Connector* connector) override;
diff --git a/device/vr/android/arcore/arcore_device_provider_factory.cc b/device/vr/android/arcore/arcore_device_provider_factory.cc index 16da7db..43ee7b6 100644 --- a/device/vr/android/arcore/arcore_device_provider_factory.cc +++ b/device/vr/android/arcore/arcore_device_provider_factory.cc
@@ -10,20 +10,20 @@ namespace device { namespace { -ARCoreDeviceProviderFactory* g_arcore_device_provider_factory = nullptr; +ArCoreDeviceProviderFactory* g_arcore_device_provider_factory = nullptr; } // namespace // static std::unique_ptr<device::VRDeviceProvider> -ARCoreDeviceProviderFactory::Create() { +ArCoreDeviceProviderFactory::Create() { if (!g_arcore_device_provider_factory) return nullptr; return g_arcore_device_provider_factory->CreateDeviceProvider(); } // static -void ARCoreDeviceProviderFactory::Install( - std::unique_ptr<ARCoreDeviceProviderFactory> factory) { +void ArCoreDeviceProviderFactory::Install( + std::unique_ptr<ArCoreDeviceProviderFactory> factory) { DCHECK_NE(g_arcore_device_provider_factory, factory.get()); if (g_arcore_device_provider_factory) delete g_arcore_device_provider_factory;
diff --git a/device/vr/android/arcore/arcore_device_provider_factory.h b/device/vr/android/arcore/arcore_device_provider_factory.h index 2b29ec28..79472ef 100644 --- a/device/vr/android/arcore/arcore_device_provider_factory.h +++ b/device/vr/android/arcore/arcore_device_provider_factory.h
@@ -13,20 +13,20 @@ class VRDeviceProvider; -class DEVICE_VR_EXPORT ARCoreDeviceProviderFactory { +class DEVICE_VR_EXPORT ArCoreDeviceProviderFactory { public: static std::unique_ptr<device::VRDeviceProvider> Create(); - static void Install(std::unique_ptr<ARCoreDeviceProviderFactory> factory); + static void Install(std::unique_ptr<ArCoreDeviceProviderFactory> factory); - virtual ~ARCoreDeviceProviderFactory() = default; + virtual ~ArCoreDeviceProviderFactory() = default; protected: - ARCoreDeviceProviderFactory() = default; + ArCoreDeviceProviderFactory() = default; virtual std::unique_ptr<device::VRDeviceProvider> CreateDeviceProvider() = 0; private: - DISALLOW_COPY_AND_ASSIGN(ARCoreDeviceProviderFactory); + DISALLOW_COPY_AND_ASSIGN(ArCoreDeviceProviderFactory); }; } // namespace device
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc index c47946f2..a8a3118d 100644 --- a/device/vr/android/gvr/gvr_device.cc +++ b/device/vr/android/gvr/gvr_device.cc
@@ -135,29 +135,10 @@ } // namespace -std::unique_ptr<GvrDevice> GvrDevice::Create() { - std::unique_ptr<GvrDevice> device = base::WrapUnique(new GvrDevice()); - if (!device->gvr_api_) - return nullptr; - return device; -} - GvrDevice::GvrDevice() : VRDeviceBase(mojom::XRDeviceId::GVR_DEVICE_ID), exclusive_controller_binding_(this), weak_ptr_factory_(this) { - GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider(); - if (!delegate_provider || delegate_provider->ShouldDisableGvrDevice()) - return; - JNIEnv* env = base::android::AttachCurrentThread(); - non_presenting_context_.Reset( - Java_NonPresentingGvrContext_create(env, reinterpret_cast<jlong>(this))); - if (!non_presenting_context_.obj()) - return; - jlong context = Java_NonPresentingGvrContext_getNativeGvrContext( - env, non_presenting_context_); - gvr_api_ = gvr::GvrApi::WrapNonOwned(reinterpret_cast<gvr_context*>(context)); - SetVRDisplayInfo(CreateVRDisplayInfo(gvr_api_.get(), GetId())); GvrDelegateProviderFactory::SetDevice(this); } @@ -179,9 +160,18 @@ void GvrDevice::RequestSession( mojom::XRRuntimeSessionOptionsPtr options, mojom::XRRuntime::RequestSessionCallback callback) { + if (!gvr_api_) { + EnsureGvrReady(); + if (!gvr_api_) { + std::move(callback).Run(nullptr, nullptr); + return; + } + } + if (!options->immersive) { // TODO(https://crbug.com/695937): This should be NOTREACHED() once we no - // longer need the hacked GRV non-immersive mode. + // longer need the hacked GRV non-immersive mode. This should now only be + // hit if orientation devices are disabled by flag. ReturnNonImmersiveSession(std::move(callback)); return; } @@ -243,8 +233,36 @@ exclusive_controller_binding_.Close(); } +void GvrDevice::EnsureGvrReady() { + if (!non_presenting_context_.obj() || !gvr_api_) { + GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider(); + if (!delegate_provider || delegate_provider->ShouldDisableGvrDevice()) + return; + JNIEnv* env = base::android::AttachCurrentThread(); + non_presenting_context_.Reset(Java_NonPresentingGvrContext_create( + env, reinterpret_cast<jlong>(this))); + if (!non_presenting_context_.obj()) + return; + jlong context = Java_NonPresentingGvrContext_getNativeGvrContext( + env, non_presenting_context_); + gvr_api_ = + gvr::GvrApi::WrapNonOwned(reinterpret_cast<gvr_context*>(context)); + SetVRDisplayInfo(CreateVRDisplayInfo(gvr_api_.get(), GetId())); + + if (paused_) { + PauseTracking(); + } else { + ResumeTracking(); + } + } +} + void GvrDevice::OnMagicWindowFrameDataRequest( mojom::XRFrameDataProvider::GetFrameDataCallback callback) { + if (!gvr_api_) { + std::move(callback).Run(nullptr); + return; + } mojom::XRFrameDataPtr frame_data = mojom::XRFrameData::New(); frame_data->pose = GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), nullptr); @@ -259,15 +277,26 @@ } void GvrDevice::PauseTracking() { - gvr_api_->PauseTracking(); - JNIEnv* env = base::android::AttachCurrentThread(); - Java_NonPresentingGvrContext_pause(env, non_presenting_context_); + paused_ = true; + if (gvr_api_ && non_presenting_context_.obj()) { + gvr_api_->PauseTracking(); + JNIEnv* env = base::android::AttachCurrentThread(); + Java_NonPresentingGvrContext_pause(env, non_presenting_context_); + } } void GvrDevice::ResumeTracking() { - gvr_api_->ResumeTracking(); - JNIEnv* env = base::android::AttachCurrentThread(); - Java_NonPresentingGvrContext_resume(env, non_presenting_context_); + paused_ = false; + if (gvr_api_ && non_presenting_context_.obj()) { + gvr_api_->ResumeTracking(); + JNIEnv* env = base::android::AttachCurrentThread(); + Java_NonPresentingGvrContext_resume(env, non_presenting_context_); + } +} + +void GvrDevice::EnsureInitialized(EnsureInitializedCallback callback) { + EnsureGvrReady(); + std::move(callback).Run(); } GvrDelegateProvider* GvrDevice::GetGvrDelegateProvider() { @@ -281,6 +310,7 @@ void GvrDevice::OnDisplayConfigurationChanged(JNIEnv* env, const JavaRef<jobject>& obj) { + DCHECK(gvr_api_); SetVRDisplayInfo(CreateVRDisplayInfo(gvr_api_.get(), GetId())); }
diff --git a/device/vr/android/gvr/gvr_device.h b/device/vr/android/gvr/gvr_device.h index 1d802b2..93388c05 100644 --- a/device/vr/android/gvr/gvr_device.h +++ b/device/vr/android/gvr/gvr_device.h
@@ -21,7 +21,7 @@ class DEVICE_VR_EXPORT GvrDevice : public VRDeviceBase, public mojom::XRSessionController { public: - static std::unique_ptr<GvrDevice> Create(); + GvrDevice(); ~GvrDevice() override; // VRDeviceBase @@ -30,6 +30,7 @@ mojom::XRRuntime::RequestSessionCallback callback) override; void PauseTracking() override; void ResumeTracking() override; + void EnsureInitialized(EnsureInitializedCallback callback) override; void OnDisplayConfigurationChanged( JNIEnv* env, @@ -52,13 +53,14 @@ void OnPresentingControllerMojoConnectionError(); void StopPresenting(); - - GvrDevice(); + void EnsureGvrReady(); GvrDelegateProvider* GetGvrDelegateProvider(); base::android::ScopedJavaGlobalRef<jobject> non_presenting_context_; std::unique_ptr<gvr::GvrApi> gvr_api_; + bool paused_ = true; + mojo::Binding<mojom::XRSessionController> exclusive_controller_binding_; base::WeakPtrFactory<GvrDevice> weak_ptr_factory_;
diff --git a/device/vr/android/gvr/gvr_device_provider.cc b/device/vr/android/gvr/gvr_device_provider.cc index 56f8e79..67c7dcb 100644 --- a/device/vr/android/gvr/gvr_device_provider.cc +++ b/device/vr/android/gvr/gvr_device_provider.cc
@@ -4,6 +4,7 @@ #include "device/vr/android/gvr/gvr_device_provider.h" +#include "base/android/build_info.h" #include "device/vr/android/gvr/gvr_device.h" namespace device { @@ -17,7 +18,12 @@ mojom::XRRuntimePtr)> add_device_callback, base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback, base::OnceClosure initialization_complete) { - vr_device_ = GvrDevice::Create(); + // Version check should match MIN_SDK_VERSION in VrCoreVersionChecker.java. + // We only expose GvrDevice if we could potentially install VRServices to + // support presentation. + if (base::android::BuildInfo::GetInstance()->sdk_int() >= + base::android::SDK_VERSION_KITKAT) + vr_device_ = base::WrapUnique(new GvrDevice()); if (vr_device_) add_device_callback.Run(vr_device_->GetId(), vr_device_->GetVRDisplayInfo(), vr_device_->BindXRRuntimePtr());
diff --git a/device/vr/public/mojom/isolated_xr_service.mojom b/device/vr/public/mojom/isolated_xr_service.mojom index 3fede7aa..ca921e0 100644 --- a/device/vr/public/mojom/isolated_xr_service.mojom +++ b/device/vr/public/mojom/isolated_xr_service.mojom
@@ -72,8 +72,13 @@ // The browser may register for changes to a device. Initial VRDisplayInfo // will immediately be returned to the listener to prevent races. - ListenToDeviceChanges(XRRuntimeEventListener listener) => - (VRDisplayInfo display_info); + ListenToDeviceChanges(associated XRRuntimeEventListener listener) => + (VRDisplayInfo? display_info); + + // Ensure that the runtime has installed all prerequisites, and is ready to + // start. May result in updated display info being sent to registered + // listeners. RequestSession will fail if this hasn't been called. + EnsureInitialized() => (); SetListeningForActivate(bool listen_for_activation); };
diff --git a/device/vr/vr_device_base.cc b/device/vr/vr_device_base.cc index af19fab1..61556842 100644 --- a/device/vr/vr_device_base.cc +++ b/device/vr/vr_device_base.cc
@@ -23,7 +23,6 @@ void VRDeviceBase::ResumeTracking() {} mojom::VRDisplayInfoPtr VRDeviceBase::GetVRDisplayInfo() { - DCHECK(display_info_); return display_info_.Clone(); } @@ -46,9 +45,9 @@ } void VRDeviceBase::ListenToDeviceChanges( - mojom::XRRuntimeEventListenerPtr listener, + mojom::XRRuntimeEventListenerAssociatedPtrInfo listener_info, mojom::XRRuntime::ListenToDeviceChangesCallback callback) { - listener_ = std::move(listener); + listener_.Bind(std::move(listener_info)); std::move(callback).Run(display_info_.Clone()); } @@ -65,13 +64,8 @@ void VRDeviceBase::SetVRDisplayInfo(mojom::VRDisplayInfoPtr display_info) { DCHECK(display_info); DCHECK(display_info->id == id_); - bool initialized = !!display_info_; display_info_ = std::move(display_info); - // Don't notify when the VRDisplayInfo is initially set. - if (!initialized) - return; - if (listener_) listener_->OnDisplayInfoChanged(display_info_.Clone()); } @@ -103,6 +97,10 @@ OnListeningForActivate(is_listening); } +void VRDeviceBase::EnsureInitialized(EnsureInitializedCallback callback) { + std::move(callback).Run(); +} + void VRDeviceBase::RequestHitTest( mojom::XRRayPtr ray, mojom::XREnvironmentIntegrationProvider::RequestHitTestCallback callback) {
diff --git a/device/vr/vr_device_base.h b/device/vr/vr_device_base.h index 8d10ef5..be6daa5 100644 --- a/device/vr/vr_device_base.h +++ b/device/vr/vr_device_base.h
@@ -27,9 +27,10 @@ // VRDevice Implementation void ListenToDeviceChanges( - mojom::XRRuntimeEventListenerPtr listener, + mojom::XRRuntimeEventListenerAssociatedPtrInfo listener, mojom::XRRuntime::ListenToDeviceChangesCallback callback) final; void SetListeningForActivate(bool is_listening) override; + void EnsureInitialized(EnsureInitializedCallback callback) override; void GetFrameData(mojom::XRFrameDataProvider::GetFrameDataCallback callback); @@ -86,7 +87,7 @@ virtual void OnMagicWindowFrameDataRequest( mojom::XRFrameDataProvider::GetFrameDataCallback callback); - mojom::XRRuntimeEventListenerPtr listener_; + mojom::XRRuntimeEventListenerAssociatedPtr listener_; bool presenting_ = false;
diff --git a/device/vr/vr_device_base_unittest.cc b/device/vr/vr_device_base_unittest.cc index 318b292..952ae70b 100644 --- a/device/vr/vr_device_base_unittest.cc +++ b/device/vr/vr_device_base_unittest.cc
@@ -12,6 +12,7 @@ #include "device/vr/test/fake_vr_device.h" #include "device/vr/test/fake_vr_service_client.h" #include "device/vr/vr_device_base.h" +#include "mojo/public/cpp/bindings/associated_binding.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -72,14 +73,15 @@ MOCK_METHOD0(OnBlur, void()); MOCK_METHOD0(OnFocus, void()); MOCK_METHOD1(OnDeviceIdle, void(mojom::VRDisplayEventReason)); + MOCK_METHOD0(OnInitialized, void()); - mojom::XRRuntimeEventListenerPtr BindPtr() { - mojom::XRRuntimeEventListenerPtr ret; + mojom::XRRuntimeEventListenerAssociatedPtrInfo BindPtrInfo() { + mojom::XRRuntimeEventListenerAssociatedPtrInfo ret; binding_.Bind(mojo::MakeRequest(&ret)); return ret; } - mojo::Binding<mojom::XRRuntimeEventListener> binding_; + mojo::AssociatedBinding<mojom::XRRuntimeEventListener> binding_; }; } // namespace @@ -122,10 +124,12 @@ // will receive the "vrdevicechanged" event. TEST_F(VRDeviceTest, DeviceChangedDispatched) { auto device = MakeVRDevice(); + auto device_ptr = device->BindXRRuntimePtr(); StubVRDeviceEventListener listener; - device->ListenToDeviceChanges( - listener.BindPtr(), + device_ptr->ListenToDeviceChanges( + listener.BindPtrInfo(), base::DoNothing()); // TODO: consider getting initial info + base::RunLoop().RunUntilIdle(); EXPECT_CALL(listener, DoOnChanged(testing::_)).Times(1); device->SetVRDisplayInfoForTest(MakeVRDisplayInfo(device->GetId())); base::RunLoop().RunUntilIdle(); @@ -135,10 +139,12 @@ device::mojom::VRDisplayEventReason mounted = device::mojom::VRDisplayEventReason::MOUNTED; auto device = MakeVRDevice(); + auto device_ptr = device->BindXRRuntimePtr(); StubVRDeviceEventListener listener; - device->ListenToDeviceChanges( - listener.BindPtr(), + device_ptr->ListenToDeviceChanges( + listener.BindPtrInfo(), base::DoNothing()); // TODO: consider getting initial data + base::RunLoop().RunUntilIdle(); EXPECT_FALSE(device->ListeningForActivate()); device->SetListeningForActivate(true);
diff --git a/docs/README.md b/docs/README.md index f9e5b0f..86db0ce7 100644 --- a/docs/README.md +++ b/docs/README.md
@@ -107,6 +107,8 @@ builder migration for Chromium * [Tour of Continuous Integration UI](tour_of_luci_ui.md) - A tour of our the user interface for LUCI, our continuous integration system +* [Parsing Test Results](parsing_test_results.md) - An introduction for how to + understand the results emitted by polygerrit and CI builds. * [Closure Compilation](closure_compilation.md) - The _Closure_ JavaScript compiler * [Threading and Tasks in Chrome](threading_and_tasks.md) - How to run tasks @@ -290,7 +292,7 @@ Enabling spoken feedback (ChromeVox) on desktop Linux. * [Offscreen, Invisible and Size](accessibility/offscreen.md) - How Chrome defines offscreen, invisible and size in the accessibility tree. -* [Text to Speech](accessibility/tts.md) - Overview of text to speech in +* [Text to Speech](accessibility/tts.md) - Overview of text to speech in Chrome and Chrome OS. * [BRLTTY in Chrome OS](accessibility/brltty.md) - Chrome OS integration with BRLTTY to support refreshable braille displays
diff --git a/docs/images/parsing_test_results_build_results_1.png b/docs/images/parsing_test_results_build_results_1.png new file mode 100644 index 0000000..cfc7136 --- /dev/null +++ b/docs/images/parsing_test_results_build_results_1.png Binary files differ
diff --git a/docs/images/parsing_test_results_polygerrit.png b/docs/images/parsing_test_results_polygerrit.png new file mode 100644 index 0000000..0a7e4b9 --- /dev/null +++ b/docs/images/parsing_test_results_polygerrit.png Binary files differ
diff --git a/docs/parsing_test_results.md b/docs/parsing_test_results.md new file mode 100644 index 0000000..909877f --- /dev/null +++ b/docs/parsing_test_results.md
@@ -0,0 +1,89 @@ +# Parsing Test Results + +Chromium runs over 500,000 tests for each CL. There are many layers of UI for +parsing and interpreting these test results. This doc provides a brief guide +for navigating these UI layers. + +## Polygerrit UI + +Tests are segmented by build and test configurations. The segments are usually +referred to as *builds*. In the example below, each green and red rectangle +refers to a *build*. + + + +The name of each build usually contains enough information to get a rough idea +of the configuration. Some examples: + +* *android_compile_dbg* is a compile-only [no tests] build of Chromium for + Android, using the *debug* configuration. +* *android-kitkat-arm-rel* builds and runs tests for Chromium for Android, + using the *release* configuration on a kitkat device. +* *win7_chromium_rel_ng* builds and runs tests for Chromium on Windows, using + the release configuration on a Windows 7 device. *ng* stands for next + generation, but this has no meaning as the previous generation was already + phased out. + +Green boxes refer to builds that passed. Red boxes refer to builds that failed. +Some failed builds get automatically retried by the CQ. In this example, +*linux_chromium_rel_ng* and *mac_chromium_rel_ng* were automatically retried +[hence the two **X**s], but *win7_chromium_rel_ng* was not. The **X** on the +left is the first build, and the **X** on the right is the second build. + +Each of these boxes is a link that provides more information about the build +failure. + +## Build Results UI + +Selecting any of the build results from the previous section will navigate to +the build results UI. Each build is implemented by a [recipe] -- +effectively a Python script. Each recipe is divided into *steps*. Each *step* +represents a well-defined action, such as updating the repository to point to +tip of tree, or compiling the necessary build artifacts. + +[recipe]: https://chromium.googlesource.com/external/github.com/luci/recipes-py/+/master/doc/user_guide.md + + + +Under the **Steps and Logfiles** heading is a list of numbered *steps*. Each +*step* has a color (red, green or purple) which indicates whether the *step* +failed, succeeded, or encountered an unexpected condition. Failing steps are +also grouped into the **Results** section at the very top for convenience. + +## Build Results UI -- Overview + +Most builds follow a similar pattern. The key *steps* are listed here. + +* **bot_update** Update the repository to point to tip of tree. Apply the CL + as a patch. +* **analyze** Analyze dependencies of test suites to determine which test + suites are affected by the patch. +* **compile (with patch)** Builds test suites and associated artifacts. +* **isolate tests** Archives test suite binaries and artifacts. +* **test_pre_run.[trigger] webkit_layout_tests (with patch)** Triggers a test + suite on swarming [remote execution framework] -- in this case, + webkit_layout_tests. +* **webkit_layout_tests (with patch)** Collects the results from swarming for a + test suite. + +If all test suites pass, then the *build* is marked as a success and no further +steps are run. If at least one test suite has failures, then the failing tests +are rerun with the patch deapplied. This allows the recipe to determine if the +test failure is due to the CL or due to a problem with tip of tree. + +* **bot_update [without patch]** Deapplies the CL patch. +* **compile [without patch]** Compiles test suites. +* **isolate tests (2)** Archives test suite binaries and artifacts. +* **test_pre_run.[trigger] webkit_layout_tests (without patch)** Triggers test + suite on swarming. Only failing tests are rerun. +* **webkit_layout_tests (without patch)** Collects results from swarming. + +**Important safety notice**. When test suites are run with the patch applied, +each test is run up to N times -- any success will mark the test as a success. +When test suites are run without the patch, each failing test is run exactly N +times. Any failure will mark the test as a failure. + +If there are tests that failed with the patch applied, but not with the patch +deapplied, then that implies that it's likely that the CL broke a test. Just to +confirm, the first suite of steps is run again, this time with the suffix +**(retry with patch)**.
diff --git a/docs/static_initializers.md b/docs/static_initializers.md index 7fcd3297..8226922e 100644 --- a/docs/static_initializers.md +++ b/docs/static_initializers.md
@@ -9,7 +9,7 @@ # How Static Initializers are Checked * For Linux and Mac: - * The expected count is stored in [//tools/perf_expectations/perf_expectations.json](https://cs.chromium.org/chromium/src/tools/perf_expectations/perf_expectations.json) + * The expected count is stored in [//infra/scripts/legacy/scripts/slave/chromium/sizes.py](https://cs.chromium.org/chromium/src/infra/scripts/legacy/scripts/slave/chromium/sizes.py) * For Android: * The expected count is stored in the build target [//chrome/android:monochrome_static_initializers](https://cs.chromium.org/chromium/src/chrome/android/BUILD.gn)
diff --git a/extensions/browser/api/storage/local_value_store_cache.cc b/extensions/browser/api/storage/local_value_store_cache.cc index d0652c52..70aa853b 100644 --- a/extensions/browser/api/storage/local_value_store_cache.cc +++ b/extensions/browser/api/storage/local_value_store_cache.cc
@@ -7,6 +7,7 @@ #include <stddef.h> #include <limits> +#include <utility> #include "content/public/browser/browser_thread.h" #include "extensions/browser/api/storage/backend_task_runner.h" @@ -34,8 +35,8 @@ } // namespace LocalValueStoreCache::LocalValueStoreCache( - const scoped_refptr<ValueStoreFactory>& factory) - : storage_factory_(factory), quota_(GetLocalQuotaLimits()) { + scoped_refptr<ValueStoreFactory> factory) + : storage_factory_(std::move(factory)), quota_(GetLocalQuotaLimits()) { DCHECK_CURRENTLY_ON(BrowserThread::UI); }
diff --git a/extensions/browser/api/storage/local_value_store_cache.h b/extensions/browser/api/storage/local_value_store_cache.h index 56277f0..7507d987 100644 --- a/extensions/browser/api/storage/local_value_store_cache.h +++ b/extensions/browser/api/storage/local_value_store_cache.h
@@ -21,8 +21,7 @@ // another for extensions. Each backend takes care of persistence. class LocalValueStoreCache : public ValueStoreCache { public: - explicit LocalValueStoreCache( - const scoped_refptr<ValueStoreFactory>& factory); + explicit LocalValueStoreCache(scoped_refptr<ValueStoreFactory> factory); ~LocalValueStoreCache() override; // ValueStoreCache implementation:
diff --git a/extensions/browser/api/storage/storage_frontend.cc b/extensions/browser/api/storage/storage_frontend.cc index 571472a..e550cd2e 100644 --- a/extensions/browser/api/storage/storage_frontend.cc +++ b/extensions/browser/api/storage/storage_frontend.cc
@@ -78,23 +78,23 @@ // static std::unique_ptr<StorageFrontend> StorageFrontend::CreateForTesting( - const scoped_refptr<ValueStoreFactory>& storage_factory, + scoped_refptr<ValueStoreFactory> storage_factory, BrowserContext* context) { - return base::WrapUnique(new StorageFrontend(storage_factory, context)); + return base::WrapUnique( + new StorageFrontend(std::move(storage_factory), context)); } StorageFrontend::StorageFrontend(BrowserContext* context) : StorageFrontend(ExtensionSystem::Get(context)->store_factory(), context) { } -StorageFrontend::StorageFrontend( - const scoped_refptr<ValueStoreFactory>& factory, - BrowserContext* context) +StorageFrontend::StorageFrontend(scoped_refptr<ValueStoreFactory> factory, + BrowserContext* context) : browser_context_(context) { - Init(factory); + Init(std::move(factory)); } -void StorageFrontend::Init(const scoped_refptr<ValueStoreFactory>& factory) { +void StorageFrontend::Init(scoped_refptr<ValueStoreFactory> factory) { TRACE_EVENT0("browser,startup", "StorageFrontend::Init") SCOPED_UMA_HISTOGRAM_TIMER("Extensions.StorageFrontendInitTime");
diff --git a/extensions/browser/api/storage/storage_frontend.h b/extensions/browser/api/storage/storage_frontend.h index c43b81e..71dd7c21 100644 --- a/extensions/browser/api/storage/storage_frontend.h +++ b/extensions/browser/api/storage/storage_frontend.h
@@ -32,7 +32,7 @@ // Creates with a specific |storage_factory|. static std::unique_ptr<StorageFrontend> CreateForTesting( - const scoped_refptr<ValueStoreFactory>& storage_factory, + scoped_refptr<ValueStoreFactory> storage_factory, content::BrowserContext* context); // Public so tests can create and delete their own instances. @@ -75,10 +75,10 @@ explicit StorageFrontend(content::BrowserContext* context); // Constructor for tests. - StorageFrontend(const scoped_refptr<ValueStoreFactory>& storage_factory, + StorageFrontend(scoped_refptr<ValueStoreFactory> storage_factory, content::BrowserContext* context); - void Init(const scoped_refptr<ValueStoreFactory>& storage_factory); + void Init(scoped_refptr<ValueStoreFactory> storage_factory); // The (non-incognito) browser context this Frontend belongs to. content::BrowserContext* const browser_context_;
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn index 11d9211..49ae13d 100644 --- a/extensions/common/BUILD.gn +++ b/extensions/common/BUILD.gn
@@ -245,10 +245,6 @@ "permissions/manifest_permission.h", "permissions/manifest_permission_set.cc", "permissions/manifest_permission_set.h", - "permissions/media_galleries_permission.cc", - "permissions/media_galleries_permission.h", - "permissions/media_galleries_permission_data.cc", - "permissions/media_galleries_permission_data.h", "permissions/permission_message.cc", "permissions/permission_message.h", "permissions/permission_message_provider.cc",
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h index c03cae1a..583023a 100644 --- a/extensions/common/extension_messages.h +++ b/extensions/common/extension_messages.h
@@ -18,14 +18,13 @@ #include "content/public/common/socket_permission_request.h" #include "extensions/common/api/messaging/message.h" #include "extensions/common/api/messaging/port_id.h" -#include "extensions/common/constants.h" #include "extensions/common/common_param_traits.h" +#include "extensions/common/constants.h" #include "extensions/common/draggable_region.h" #include "extensions/common/event_filtering_info.h" #include "extensions/common/extension.h" #include "extensions/common/extensions_client.h" #include "extensions/common/host_id.h" -#include "extensions/common/permissions/media_galleries_permission_data.h" #include "extensions/common/permissions/permission_set.h" #include "extensions/common/permissions/socket_permission_data.h" #include "extensions/common/permissions/usb_device_permission_data.h" @@ -264,10 +263,6 @@ IPC_STRUCT_TRAITS_MEMBER(interface_class()) IPC_STRUCT_TRAITS_END() -IPC_STRUCT_TRAITS_BEGIN(extensions::MediaGalleriesPermissionData) - IPC_STRUCT_TRAITS_MEMBER(permission()) -IPC_STRUCT_TRAITS_END() - IPC_STRUCT_TRAITS_BEGIN(extensions::Message) IPC_STRUCT_TRAITS_MEMBER(data) IPC_STRUCT_TRAITS_MEMBER(user_gesture)
diff --git a/gpu/command_buffer/service/client_service_map.h b/gpu/command_buffer/service/client_service_map.h index af3098a..42974ae5 100644 --- a/gpu/command_buffer/service/client_service_map.h +++ b/gpu/command_buffer/service/client_service_map.h
@@ -63,33 +63,35 @@ client_to_service_map_.clear(); } - bool GetServiceID(ClientType client_id, ServiceType* service_id) const { - if (client_id < kMaxFlatArraySize) { - if (client_id < client_to_service_array_.size() && - client_to_service_array_[client_id] != invalid_service_id()) { - if (service_id) { - *service_id = client_to_service_array_[client_id]; - } - return true; - } - } else { - auto iter = client_to_service_map_.find(client_id); - if (iter != client_to_service_map_.end()) { - if (service_id) { - *service_id = iter->second; - } - return true; - } + ALWAYS_INLINE bool GetServiceID(ClientType client_id, + ServiceType* service_id) const { + DCHECK(service_id); + if (client_id >= kMaxFlatArraySize) { + return GetServiceIDFromMap(client_id, service_id); + } + + if (client_id < client_to_service_array_.size() && + client_to_service_array_[client_id] != invalid_service_id()) { + *service_id = client_to_service_array_[client_id]; + return true; } if (client_id == 0) { - if (service_id) { - *service_id = 0; - } + *service_id = 0; return true; } return false; } + ALWAYS_INLINE bool HasClientID(ClientType client_id) const { + if (client_id >= kMaxFlatArraySize) { + return GetServiceIDFromMap(client_id, nullptr); + } + + return client_id == 0 || + (client_id < client_to_service_array_.size() && + client_to_service_array_[client_id] != invalid_service_id()); + } + ServiceType GetServiceIDOrInvalid(ClientType client_id) { ServiceType service_id; if (GetServiceID(client_id, &service_id)) { @@ -118,10 +120,7 @@ } } if (service_id == 0) { - if (client_id) { - *client_id = 0; - } - return true; + *client_id = 0; } return false; } @@ -148,6 +147,19 @@ static constexpr size_t kMaxFlatArraySize = 0x4000; private: + bool GetServiceIDFromMap(ClientType client_id, + ServiceType* service_id) const { + DCHECK(client_id >= kMaxFlatArraySize); + auto iter = client_to_service_map_.find(client_id); + if (iter != client_to_service_map_.end()) { + if (service_id) { + *service_id = iter->second; + } + return true; + } + return false; + } + ServiceType invalid_service_id_; std::vector<ServiceType> client_to_service_array_; std::unordered_map<ClientType, ServiceType> client_to_service_map_;
diff --git a/gpu/command_buffer/service/client_service_map_unittest.cc b/gpu/command_buffer/service/client_service_map_unittest.cc index 6c11337..c16d42a 100644 --- a/gpu/command_buffer/service/client_service_map_unittest.cc +++ b/gpu/command_buffer/service/client_service_map_unittest.cc
@@ -25,7 +25,7 @@ EXPECT_EQ(kServiceId, service_id); // Check null is handled for GetServiceID - EXPECT_TRUE(map.GetServiceID(kClientId, nullptr)); + EXPECT_TRUE(map.HasClientID(kClientId)); // Check service -> client ID lookup MapDataType client_id = 0; @@ -90,19 +90,19 @@ ClientServiceMapType map; map.SetIDMapping(kClientId, kServiceId); - EXPECT_TRUE(map.GetServiceID(kClientId, nullptr)); + EXPECT_TRUE(map.HasClientID(kClientId)); map.RemoveClientID(kClientId); - EXPECT_FALSE(map.GetServiceID(kClientId, nullptr)); + EXPECT_FALSE(map.HasClientID(kClientId)); map.SetIDMapping(kClientId, kServiceId); - EXPECT_TRUE(map.GetServiceID(kClientId, nullptr)); + EXPECT_TRUE(map.HasClientID(kClientId)); map.Clear(); - EXPECT_FALSE(map.GetServiceID(kClientId, nullptr)); + EXPECT_FALSE(map.HasClientID(kClientId)); map.SetIDMapping(kClientId, kLargeServiceId); - EXPECT_TRUE(map.GetServiceID(kClientId, nullptr)); + EXPECT_TRUE(map.HasClientID(kClientId)); map.RemoveClientID(kClientId); - EXPECT_FALSE(map.GetServiceID(kClientId, nullptr)); + EXPECT_FALSE(map.HasClientID(kClientId)); } TEST(ClientServiceMap, ManyIDs) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc index 6e7ae295..e4b21a6 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -143,13 +143,12 @@ bool have_context = !!api; // Only delete textures that are not referenced by a TexturePassthrough // object, they handle their own deletion once all references are lost - DeleteServiceObjects( - &texture_id_map, have_context, - [this, api](GLuint client_id, GLuint texture) { - if (!texture_object_map.GetServiceID(client_id, nullptr)) { - api->glDeleteTexturesFn(1, &texture); - } - }); + DeleteServiceObjects(&texture_id_map, have_context, + [this, api](GLuint client_id, GLuint texture) { + if (!texture_object_map.HasClientID(client_id)) { + api->glDeleteTexturesFn(1, &texture); + } + }); DeleteServiceObjects(&buffer_id_map, have_context, [api](GLuint client_id, GLuint buffer) { api->glDeleteBuffersARBFn(1, &buffer);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc index 35d6cc9..9b09e7f 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -26,7 +26,7 @@ DCHECK(n >= 0); std::vector<ClientType> client_ids_copy(client_ids, client_ids + n); for (GLsizei ii = 0; ii < n; ++ii) { - if (id_map->GetServiceID(client_ids_copy[ii], nullptr)) { + if (id_map->HasClientID(client_ids_copy[ii])) { return error::kInvalidArguments; } } @@ -47,7 +47,7 @@ error::Error CreateHelper(ClientType client_id, ClientServiceMap<ClientType, ServiceType>* id_map, GenFunction create_function) { - if (id_map->GetServiceID(client_id, nullptr)) { + if (id_map->HasClientID(client_id)) { return error::kInvalidArguments; } ServiceType service_id = create_function(); @@ -110,12 +110,19 @@ GLuint client_id, PassthroughResources* resources, bool create_if_missing) { - return GetServiceID(client_id, &resources->texture_id_map, create_if_missing, - [api]() { - GLuint service_id = 0; - api->glGenTexturesFn(1, &service_id); - return service_id; - }); + GLuint service_id = resources->texture_id_map.invalid_service_id(); + if (resources->texture_id_map.GetServiceID(client_id, &service_id)) { + return service_id; + } + + if (create_if_missing) { + GLuint service_id = 0; + api->glGenTexturesFn(1, &service_id); + resources->texture_id_map.SetIDMapping(client_id, service_id); + return service_id; + } + + return resources->texture_id_map.invalid_service_id(); } GLuint GetBufferServiceID(gl::GLApi* api, @@ -1091,7 +1098,7 @@ error::Error GLES2DecoderPassthroughImpl::DoFenceSync(GLenum condition, GLbitfield flags, GLuint client_id) { - if (resources_->sync_id_map.GetServiceID(client_id, nullptr)) { + if (resources_->sync_id_map.HasClientID(client_id)) { return error::kInvalidArguments; } @@ -4038,7 +4045,7 @@ GLuint texture_client_id, const volatile GLbyte* mailbox) { if (!texture_client_id || - resources_->texture_id_map.GetServiceID(texture_client_id, nullptr)) { + resources_->texture_id_map.HasClientID(texture_client_id)) { return error::kInvalidArguments; }
diff --git a/gpu/ipc/service/command_buffer_stub.cc b/gpu/ipc/service/command_buffer_stub.cc index f76e4a8..ed7e19a 100644 --- a/gpu/ipc/service/command_buffer_stub.cc +++ b/gpu/ipc/service/command_buffer_stub.cc
@@ -707,8 +707,8 @@ void CommandBufferStub::OnWaitSyncTokenCompleted(const SyncToken& sync_token) { DCHECK(waiting_for_sync_point_); - TRACE_EVENT_ASYNC_END1("gpu", "WaitSyncTokenCompleted", this, - "CommandBufferStub", this); + TRACE_EVENT_ASYNC_END1("gpu", "WaitSyncToken", this, "CommandBufferStub", + this); // Don't call PullTextureUpdates here because we can't MakeCurrent if we're // executing commands on another context. The WaitSyncToken command will run // again and call PullTextureUpdates once this command buffer gets scheduled.
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg index 635fb38..9d896f14 100644 --- a/infra/config/global/luci-milo.cfg +++ b/infra/config/global/luci-milo.cfg
@@ -143,7 +143,7 @@ } links { text: "perf.fyi" - url: "/p/chromium/g/chromium.perf.fyi" + url: "/p/chrome/g/chrome.perf.fyi/console" alt: "Chromium Perf FYI console" } links { @@ -3697,78 +3697,6 @@ consoles { header_id: "chromium" - id: "chromium.perf.fyi" - name: "chromium.perf.fyi" - repo_url: "https://chromium.googlesource.com/chromium/src" - refs: "refs/heads/master" - manifest_name: "REVISION" - builders { - name: "buildbot/chromium.perf.fyi/Android Builder Perf FYI" - name: "buildbucket/luci.chromium.ci/Android Builder Perf FYI" - category: "android" - } - builders { - name: "buildbot/chromium.perf.fyi/Android arm64 Builder Perf FYI" - name: "buildbucket/luci.chromium.ci/Android arm64 Builder Perf FYI" - category: "android" - } - builders { - name: "buildbot/chromium.perf.fyi/Android CFI Builder Perf FYI" - name: "buildbucket/luci.chromium.ci/Android CFI Builder Perf FYI" - category: "android" - } - builders { - name: "buildbot/chromium.perf.fyi/Android CFI arm64 Builder Perf FYI" - name: "buildbucket/luci.chromium.ci/Android CFI arm64 Builder Perf FYI" - category: "android" - } - builders { - name: "buildbot/chromium.perf.fyi/Linux Compile Perf FYI" - name: "buildbucket/luci.chromium.ci/Linux Compile Perf FYI" - category: "linux" - } - builders { - name: "buildbot/chromium.perf.fyi/Android Nexus 5X Perf FYI" - name: "buildbucket/luci.chromium.ci/Android Nexus 5X Perf FYI" - category: "android" - } - builders { - name: "buildbot/chromium.perf.fyi/android-pixel2-perf" - name: "buildbucket/luci.chromium.ci/android-pixel2-perf" - category: "android" - } - builders { - name: "buildbot/chromium.perf.fyi/android-pixel2_webview-perf" - name: "buildbucket/luci.chromium.ci/android-pixel2_webview-perf" - category: "android" - } - builders { - name: "buildbot/chromium.perf.fyi/android-go_webview-perf" - name: "buildbucket/luci.chromium.ci/android-go_webview-perf" - category: "android" - } - builders { - name: "buildbucket/luci.chrome.ci/linux-perf-fyi" - category: "linux" - } - builders { - name: "buildbot/chromium.perf.fyi/One Buildbot Step Test Builder" - name: "buildbucket/luci.chromium.ci/One Buildbot Step Test Builder" - category: "linux" - } - builders { - name: "buildbot/chromium.perf.fyi/Mac Builder Perf FYI" - name: "buildbucket/luci.chromium.ci/Mac Builder Perf FYI" - category: "mac" - } - builders { - name: "buildbot/chromium.perf.fyi/Win Builder Perf FYI" - name: "buildbucket/luci.chromium.ci/Win Builder Perf FYI" - } -} - -consoles { - header_id: "chromium" id: "chromium.tools.build" name: "chromium.tools.build" repo_url: "https://chromium.googlesource.com/chromium/src"
diff --git a/infra/scripts/legacy/scripts/slave/chromium/sizes.py b/infra/scripts/legacy/scripts/slave/chromium/sizes.py index c1479b21..41d0137c 100755 --- a/infra/scripts/legacy/scripts/slave/chromium/sizes.py +++ b/infra/scripts/legacy/scripts/slave/chromium/sizes.py
@@ -29,10 +29,19 @@ SRC_DIR = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..', '..')) +EXPECTED_LINUX_SI_COUNTS = { + 'chrome': 8, + 'nacl_helper': 6, + 'nacl_helper_bootstrap': 0, +} + +EXPECTED_MAC_SI_COUNT = 1 + class ResultsCollector(object): def __init__(self): self.results = {} + self.failures = [] def add_result(self, name, identifier, value, units): assert name not in self.results @@ -45,6 +54,9 @@ # Legacy printing, previously used for parsing the text logs. print 'RESULT %s: %s= %s %s' % (name, identifier, value, units) + def add_failure(self, failure): + self.failures.append(failure) + def get_size(filename): return os.stat(filename)[stat.ST_SIZE] @@ -164,7 +176,11 @@ # For Release builds only, use dump-static-initializers.py to print the # list of static initializers. - if si_count > 0 and options.target == 'Release': + if si_count > EXPECTED_MAC_SI_COUNT and options.target == 'Release': + result = 125 + results_collector.add_failure( + 'Expected 0 static initializers in %s, but found %d' % + (chromium_framework_executable, si_count)) print '\n# Static initializers in %s:' % chromium_framework_executable # First look for a dSYM to get information about the initializers. If @@ -230,7 +246,7 @@ return 66 -def check_linux_binary(target_dir, binary_name, options): +def check_linux_binary(target_dir, binary_name, options, results_collector): """Collect appropriate size information about the built Linux binary given. Returns a tuple (result, sizes). result is the first non-zero exit @@ -302,16 +318,23 @@ # For Release builds only, use dump-static-initializers.py to print the list # of static initializers. - if si_count > 0 and options.target == 'Release': - build_dir = os.path.dirname(target_dir) - dump_static_initializers = os.path.join(os.path.dirname(build_dir), - 'tools', 'linux', - 'dump-static-initializers.py') - result, stdout = run_process(result, [dump_static_initializers, - '-d', binary_file]) - print '\n# Static initializers in %s:' % binary_file - print_si_fail_hint('tools/linux/dump-static-initializers.py') - print stdout + if options.target == 'Release': + if (binary_name in EXPECTED_LINUX_SI_COUNTS and + si_count > EXPECTED_LINUX_SI_COUNTS[binary_name]): + result = 125 + results_collector.add_failure( + 'Expected <= %d static initializers in %s, but found %d' % + (EXPECTED_LINUX_SI_COUNTS[binary_name], binary_name, si_count)) + if si_count > 0: + build_dir = os.path.dirname(target_dir) + dump_static_initializers = os.path.join(os.path.dirname(build_dir), + 'tools', 'linux', + 'dump-static-initializers.py') + result, stdout = run_process(result, [dump_static_initializers, + '-d', binary_file]) + print '\n# Static initializers in %s:' % binary_file + print_si_fail_hint('tools/linux/dump-static-initializers.py') + print stdout # Determine if the binary has the DT_TEXTREL marker. result, stdout = run_process(result, ['readelf', '-Wd', binary_file]) @@ -350,7 +373,8 @@ totals = {} for binary in binaries: - this_result, this_sizes = check_linux_binary(target_dir, binary, options) + this_result, this_sizes = check_linux_binary(target_dir, binary, options, + results_collector) if result == 0: result = this_result for name, identifier, totals_id, value, units in this_sizes: @@ -399,7 +423,8 @@ binaries_to_print = binaries for (binary, binary_to_print) in zip(binaries, binaries_to_print): - this_result, this_sizes = check_linux_binary(target_dir, binary, options) + this_result, this_sizes = check_linux_binary(target_dir, binary, options, + results_collector) if result == 0: result = this_result for name, identifier, _, value, units in this_sizes: @@ -534,6 +559,8 @@ help='specify platform (%s) [default: %%default]' % ', '.join(platforms)) option_parser.add_option('--json', help='Path to JSON output file') + option_parser.add_option('--failures', + help='Path to JSON output file for failures') options, args = option_parser.parse_args() @@ -554,6 +581,10 @@ with open(options.json, 'w') as f: json.dump(results_collector.results, f) + if options.failures: + with open(options.failures, 'w') as f: + json.dump(results_collector.failures, f) + return rc
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm index da03793..6d58a2b 100644 --- a/ios/chrome/browser/about_flags.mm +++ b/ios/chrome/browser/about_flags.mm
@@ -355,6 +355,11 @@ {"toolbar-container", flag_descriptions::kToolbarContainerName, flag_descriptions::kToolbarContainerDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(toolbar_container::kToolbarContainerEnabled)}, + {"toolbar-container-custom-view", + flag_descriptions::kToolbarContainerCustomViewName, + flag_descriptions::kToolbarContainerCustomViewDescription, + flags_ui::kOsIos, + FEATURE_VALUE_TYPE(toolbar_container::kToolbarContainerCustomViewEnabled)}, {"omnibox-popup-shortcuts", flag_descriptions::kOmniboxPopupShortcutIconsInZeroStateName, flag_descriptions::kOmniboxPopupShortcutIconsInZeroStateDescription, @@ -372,6 +377,10 @@ {"use-multilogin-endpoint", flag_descriptions::kUseMultiloginEndpointName, flag_descriptions::kUseMultiloginEndpointDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kUseMultiloginEndpoint)}, + {"closing-last-incognito-tab", + flag_descriptions::kClosingLastIncognitoTabName, + flag_descriptions::kClosingLastIncognitoTabDescription, flags_ui::kOsIos, + FEATURE_VALUE_TYPE(kClosingLastIncognitoTab)}, }; // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc index ba1bfc38..37daccf 100644 --- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc +++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc
@@ -4,6 +4,7 @@ #include "ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h" +#include "base/logging.h" #include "base/strings/utf_string_conversions.h" #include "components/browser_sync/profile_sync_service.h" #include "components/history/core/browser/history_service.h" @@ -104,6 +105,11 @@ return nullptr; } +OmniboxPedalProvider* AutocompleteProviderClientImpl::GetPedalProvider() const { + NOTREACHED(); + return nullptr; +} + scoped_refptr<ShortcutsBackend> AutocompleteProviderClientImpl::GetShortcutsBackend() { return ios::ShortcutsBackendFactory::GetForBrowserState(browser_state_);
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h index 56a4e005..9451c99 100644 --- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h +++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h
@@ -41,6 +41,7 @@ bool create_if_necessary) const override; DocumentSuggestionsService* GetDocumentSuggestionsService( bool create_if_necessary) const override; + OmniboxPedalProvider* GetPedalProvider() const override; scoped_refptr<ShortcutsBackend> GetShortcutsBackend() override; scoped_refptr<ShortcutsBackend> GetShortcutsBackendIfExists() override; std::unique_ptr<KeywordExtensionsDelegate> GetKeywordExtensionsDelegate(
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc index ab7e8d8..e14ac76 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -139,6 +139,12 @@ "When enabled, some network issues will trigger a test to check if a " "Captive Portal network is the cause of the issue."; +// TODO(crbug.com/893314) : Remove this flag. +const char kClosingLastIncognitoTabName[] = "Closing Last Incognito Tab"; +const char kClosingLastIncognitoTabDescription[] = + "Automatically switches to the regular tabs panel in the tab grid after " + "closing the last incognito tab"; + const char kContextualSearch[] = "Contextual Search"; const char kContextualSearchDescription[] = "Whether or not Contextual Search is enabled."; @@ -251,6 +257,11 @@ "When enabled, the toolbars and their fullscreen animations will be " "managed by the toolbar container coordinator rather than BVC."; +const char kToolbarContainerCustomViewName[] = + "Use custom toolbar container view."; +const char kToolbarContainerCustomViewDescription[] = + "Use the custom toolbar container view fix for crbug.com/889884."; + const char kUnifiedConsentName[] = "Unified Consent"; const char kUnifiedConsentDescription[] = "Enables a unified management of user consent for privacy-related "
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h index fa74a6e..88b3729e 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -110,6 +110,11 @@ extern const char kCaptivePortalMetricsName[]; extern const char kCaptivePortalMetricsDescription[]; +// Title and description for the flag to enable automatically switching to the +// regular tabs after closing the last incognito tab. +extern const char kClosingLastIncognitoTabName[]; +extern const char kClosingLastIncognitoTabDescription[]; + // Title and description for the flag to enable Contextual Search. extern const char kContextualSearch[]; extern const char kContextualSearchDescription[]; @@ -207,6 +212,11 @@ extern const char kToolbarContainerName[]; extern const char kToolbarContainerDescription[]; +// Title and description for the flag to enable the custom toolbar container +// view fix for crbug.com/889884. +extern const char kToolbarContainerCustomViewName[]; +extern const char kToolbarContainerCustomViewDescription[]; + // Title and description for the flag to enable the unified consent. extern const char kUnifiedConsentName[]; extern const char kUnifiedConsentDescription[];
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index e77d34b0..862b422 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -206,6 +206,7 @@ #import "ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h" #import "ios/chrome/browser/ui/toolbar/secondary_toolbar_coordinator.h" #import "ios/chrome/browser/ui/toolbar/toolbar_coordinator_adaptor.h" +#import "ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h" #import "ios/chrome/browser/ui/translate/language_selection_coordinator.h" #include "ios/chrome/browser/ui/ui_feature_flags.h" #include "ios/chrome/browser/ui/ui_util.h" @@ -2465,7 +2466,10 @@ if (self.secondaryToolbarCoordinator) { // Create the container view for the secondary toolbar and add it to the // hierarchy - UIView* container = [[ToolbarContainerView alloc] init]; + bool useCustomView = base::FeatureList::IsEnabled( + toolbar_container::kToolbarContainerCustomViewEnabled); + UIView* container = useCustomView ? [[ToolbarContainerView alloc] init] + : [[UIView alloc] init]; container.translatesAutoresizingMaskIntoConstraints = NO; [container addSubview:self.secondaryToolbarCoordinator.viewController.view];
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_util.mm b/ios/chrome/browser/ui/omnibox/omnibox_util.mm index f6774545..acc3d77c 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_util.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_util.mm
@@ -54,6 +54,7 @@ case AutocompleteMatchType::PHYSICAL_WEB_OVERFLOW_DEPRECATED: case AutocompleteMatchType::URL_WHAT_YOU_TYPED: case AutocompleteMatchType::DOCUMENT_SUGGESTION: + case AutocompleteMatchType::PEDAL: return DEFAULT_FAVICON; case AutocompleteMatchType::HISTORY_BODY: case AutocompleteMatchType::HISTORY_KEYWORD: @@ -184,7 +185,8 @@ DCHECK(!is_incognito); return IDR_IOS_OMNIBOX_CALCULATOR; case AutocompleteMatchType::DOCUMENT_SUGGESTION: - // Document suggeestions aren't yet supported on mobile. + case AutocompleteMatchType::PEDAL: + // Document and Pedal suggestions aren't yet supported on mobile. NOTREACHED(); return IDR_IOS_OMNIBOX_HTTP; case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_constants.h b/ios/chrome/browser/ui/tab_grid/tab_grid_constants.h index 24d6b7f..7698ae65 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_constants.h +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_constants.h
@@ -48,4 +48,8 @@ extern const CGFloat kTabGridTopToolbarHeight; extern const CGFloat kTabGridBottomToolbarHeight; +// The delay (in milliseconds) after closing the last incognito tab and before +// automatically scrolling to the regular tabs panel. +extern const int64_t kTabGridScrollAnimationDelayInMilliseconds; + #endif // IOS_CHROME_BROWSER_UI_TAB_GRID_TAB_GRID_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_constants.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_constants.mm index 6059f423..ed16470 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_constants.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_constants.mm
@@ -51,3 +51,7 @@ // Intrinsic heights of the tab grid toolbars. const CGFloat kTabGridTopToolbarHeight = 52.0f; const CGFloat kTabGridBottomToolbarHeight = 44.0f; + +// The delay (in milliseconds) after closing the last incognito tab and before +// automatically scrolling to the regular tabs panel. +const int64_t kTabGridScrollAnimationDelayInMilliseconds = 300;
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm index 7d6c701..50472e3 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -4,10 +4,12 @@ #import "ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.h" +#include "base/bind.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "base/strings/sys_string_conversions.h" +#include "base/task/post_task.h" #import "ios/chrome/browser/ui/commands/application_commands.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h" #import "ios/chrome/browser/ui/rtl_geometry.h" @@ -24,9 +26,12 @@ #import "ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.h" #import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" +#include "ios/chrome/browser/ui/ui_util.h" #import "ios/chrome/browser/ui/uikit_ui_util.h" #import "ios/chrome/common/ui_util/constraints_ui_util.h" #include "ios/chrome/grit/ios_strings.h" +#include "ios/web/public/web_task_traits.h" +#include "ios/web/public/web_thread.h" #include "ui/base/l10n/l10n_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -1173,6 +1178,16 @@ return 12; } +// Sets both the current page and page control's selected page to |page|. +// Animation is used if |animated| is YES. +- (void)setCurrentPageAndPageControlSelectedPage:(TabGridPage)page + animated:(BOOL)animated { + if (self.topToolbar.pageControl.selectedPage != page) + [self.topToolbar.pageControl setSelectedPage:page animated:animated]; + if (self.currentPage != page) + [self setCurrentPage:page animated:animated]; +} + #pragma mark - GridViewControllerDelegate - (void)gridViewController:(GridViewController*)gridViewController @@ -1232,11 +1247,31 @@ [self configureButtonsForActiveAndCurrentPage]; if (gridViewController == self.regularTabsViewController) { self.topToolbar.pageControl.regularTabCount = count; - } else if (gridViewController == self.incognitoTabsViewController) { - if (count == 0) { - [self.topToolbar.pageControl setSelectedPage:TabGridPageRegularTabs - animated:YES]; - [self setCurrentPage:TabGridPageRegularTabs animated:YES]; + } else if (IsClosingLastIncognitoTabEnabled() && + gridViewController == self.incognitoTabsViewController) { + // No assumption is made as to the state of the UI. This method can be + // called with an incognito view controller and a current page that is not + // the incognito tabs. + if (count == 0 && self.currentPage == TabGridPageIncognitoTabs) { + // Show the regular tabs to the user if the last incognito tab is closed. + if (self.viewLoaded && self.view.window) { + // Visibly scroll to the regular tabs panel after a slight delay when + // the user is already in the tab switcher. + __weak TabGridViewController* weakSelf = self; + base::PostDelayedTaskWithTraits( + FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{ + [weakSelf setCurrentPageAndPageControlSelectedPage: + TabGridPageRegularTabs + animated:YES]; + }), + base::TimeDelta::FromMilliseconds( + kTabGridScrollAnimationDelayInMilliseconds)); + } else { + // Directly show the regular tabs in tab switcher without animation if + // the user was not already in tab switcher. + [self setCurrentPageAndPageControlSelectedPage:TabGridPageRegularTabs + animated:NO]; + } } }
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h b/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h index ad801815..375ef80 100644 --- a/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h +++ b/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h
@@ -9,6 +9,12 @@ namespace toolbar_container { +// Used to enable the fix for crbug.com/889884. This is a temporary flag that +// is only going to be used as an emergency shutoff for the bug fix because it +// was landed late in the branch. +// TODO(crbug.com/880672): Remove this flag. +extern const base::Feature kToolbarContainerCustomViewEnabled; + // Used to move toolbar layout management to a container view. extern const base::Feature kToolbarContainerEnabled;
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.mm index c591526..2685a41 100644 --- a/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.mm +++ b/ios/chrome/browser/ui/toolbar_container/toolbar_container_features.mm
@@ -10,6 +10,9 @@ namespace toolbar_container { +const base::Feature kToolbarContainerCustomViewEnabled{ + "ToolbarContainerCustomViewEnabled", base::FEATURE_ENABLED_BY_DEFAULT}; + const base::Feature kToolbarContainerEnabled{"ToolbarContainerEnabled", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc index bb1defa..2140fbf 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.cc +++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -7,6 +7,10 @@ const base::Feature kFirstResponderKeyWindow{"FirstResponderKeyWindow", base::FEATURE_ENABLED_BY_DEFAULT}; +// TODO(crbug.com/893314) : Remove this flag. +const base::Feature kClosingLastIncognitoTab{"ClosingLastIncognitoTab", + base::FEATURE_ENABLED_BY_DEFAULT}; + const base::Feature kCopyImage{"CopyImage", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kOmniboxPopupShortcutIconsInZeroState{
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h index abdb4c7..85ea4b12 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.h +++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -12,6 +12,10 @@ // responder. extern const base::Feature kFirstResponderKeyWindow; +// Feature to automatically switch to the regular tabs panel in tab grid after +// closing the last incognito tab. +extern const base::Feature kClosingLastIncognitoTab; + // Feature to copy image to system pasteboard via context menu. extern const base::Feature kCopyImage;
diff --git a/ios/chrome/browser/ui/ui_util.h b/ios/chrome/browser/ui/ui_util.h index c54a28e..ba69dcc 100644 --- a/ios/chrome/browser/ui/ui_util.h +++ b/ios/chrome/browser/ui/ui_util.h
@@ -39,6 +39,10 @@ // Returns true if the device is an iPhone X. bool IsIPhoneX(); +// Returns whether the flag is enabled for switching to the regular tabs panel +// in tab switcher when the last incognito tab is closed. +bool IsClosingLastIncognitoTabEnabled(); + // Returns whether the UI Refresh Location Bar will be used. // TODO (crbug.com/884723): Remove all use of this flag. bool IsRefreshLocationBarEnabled();
diff --git a/ios/chrome/browser/ui/ui_util.mm b/ios/chrome/browser/ui/ui_util.mm index f20294c5..577440a 100644 --- a/ios/chrome/browser/ui/ui_util.mm +++ b/ios/chrome/browser/ui/ui_util.mm
@@ -60,6 +60,11 @@ (height == 2436 || height == 2688 || height == 1792)); } +// TODO(crbug.com/893314) : Remove this flag. +bool IsClosingLastIncognitoTabEnabled() { + return base::FeatureList::IsEnabled(kClosingLastIncognitoTab); +} + bool IsRefreshLocationBarEnabled() { return true; }
diff --git a/ios/chrome/browser/web/window_open_by_dom_egtest.mm b/ios/chrome/browser/web/window_open_by_dom_egtest.mm index 2aeaa03..8ac3b50 100644 --- a/ios/chrome/browser/web/window_open_by_dom_egtest.mm +++ b/ios/chrome/browser/web/window_open_by_dom_egtest.mm
@@ -267,20 +267,6 @@ assertWithMatcher:grey_notNil()]; } -// Tests opening a child window using the following link -// <a href="data:text/html,<script>window.location='about:newtab';</script>" -// target="_blank"> -- (void)testWindowOpenWithAboutNewTabScript { - const char ID[] = "webScenarioWindowOpenWithAboutNewTabScript"; - [[EarlGrey selectElementWithMatcher:WebViewInWebState(GetCurrentWebState())] - performAction:web::WebViewTapElement( - GetCurrentWebState(), - ElementSelector::ElementSelectorId(ID))]; - [ChromeEarlGrey waitForMainTabCount:2]; - [[EarlGrey selectElementWithMatcher:OmniboxText("about:newtab")] - assertWithMatcher:grey_notNil()]; -} - // Tests that closing the current window using DOM fails. - (void)testCloseWindowNotOpenByDOM { GREYAssert(TapWebViewElementWithId("webScenarioWindowClose"),
diff --git a/ios/testing/data/http_server_files/window_open.html b/ios/testing/data/http_server_files/window_open.html index 36b5e167..2ffbcaf2 100644 --- a/ios/testing/data/http_server_files/window_open.html +++ b/ios/testing/data/http_server_files/window_open.html
@@ -139,18 +139,6 @@ <td>about:blank opened in a new window, with an href and a preventDefault<br></td> </tr> - <tr id="_webScenarioWindowOpenWithAboutNewTabScript"> - <td> - <a href="data:text/html,<script>window.location='about:newtab';</script>" - target="_blank" - name="webScenarioWindowOpenWithAboutNewTabScript" - id="webScenarioWindowOpenWithAboutNewTabScript"> - webScenarioWindowOpenWithAboutNewTabScript - </a> - </td> - <td>about:blank opened in a new window, using "window.location='about:newtab" script<br></td> - </tr> - <tr id="_webScenarioWindowOpenAndSetLocation"> <td> <script>
diff --git a/ios/web/download/download_task_impl.mm b/ios/web/download/download_task_impl.mm index 86bd8d0f..55dc87a1 100644 --- a/ios/web/download/download_task_impl.mm +++ b/ios/web/download/download_task_impl.mm
@@ -41,10 +41,10 @@ // Translates an CFNetwork error code to a net error code. Returns 0 if |error| // is nil. -int GetNetErrorCodeFromNSError(NSError* error) { +int GetNetErrorCodeFromNSError(NSError* error, NSURL* url) { int error_code = 0; if (error) { - if (!web::GetNetErrorFromIOSErrorCode(error.code, &error_code)) { + if (!web::GetNetErrorFromIOSErrorCode(error.code, &error_code, url)) { error_code = net::ERR_FAILED; } } @@ -337,7 +337,8 @@ return; } - error_code_ = GetNetErrorCodeFromNSError(error); + error_code_ = + GetNetErrorCodeFromNSError(error, task.currentRequest.URL); percent_complete_ = GetTaskPercentComplete(task); received_bytes_ = task.countOfBytesReceived; if (total_bytes_ == -1 || task.countOfBytesExpectedToReceive) {
diff --git a/ios/web/web_state/BUILD.gn b/ios/web/web_state/BUILD.gn index 3bd3c67..ccf460c 100644 --- a/ios/web/web_state/BUILD.gn +++ b/ios/web/web_state/BUILD.gn
@@ -103,6 +103,7 @@ deps = [ "//base", "//ios/net", + "//ios/web/public", "//net", ]
diff --git a/ios/web/web_state/error_translation_util.h b/ios/web/web_state/error_translation_util.h index b71fbc42..6449a085 100644 --- a/ios/web/web_state/error_translation_util.h +++ b/ios/web/web_state/error_translation_util.h
@@ -10,8 +10,11 @@ namespace web { // Translates an CFNetwork error code to a net error code using |net_error_code| -// as an out-parameter. Returns true if a valid translation was found. -bool GetNetErrorFromIOSErrorCode(NSInteger ios_error_code, int* net_error_code); +// as an out-parameter. |url| is URL which failed to load. Returns true if a +// valid translation was found. +bool GetNetErrorFromIOSErrorCode(NSInteger ios_error_code, + int* net_error_code, + NSURL* url); // Translates an iOS-specific error into its net error equivalent and returns a // copy of |error| with the translation as its final underlying error. The
diff --git a/ios/web/web_state/error_translation_util.mm b/ios/web/web_state/error_translation_util.mm index 2559072..de2f3084 100644 --- a/ios/web/web_state/error_translation_util.mm +++ b/ios/web/web_state/error_translation_util.mm
@@ -5,10 +5,14 @@ #import "ios/web/web_state/error_translation_util.h" #include <CFNetwork/CFNetwork.h> +#include <Foundation/Foundation.h> #import "base/ios/ns_error_util.h" #import "ios/net/protocol_handler_util.h" +#import "ios/web/public/web_client.h" +#import "net/base/mac/url_conversions.h" #include "net/base/net_errors.h" +#include "url/gurl.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -17,7 +21,8 @@ namespace web { bool GetNetErrorFromIOSErrorCode(NSInteger ios_error_code, - int* net_error_code) { + int* net_error_code, + NSURL* url) { DCHECK(net_error_code); bool translation_success = true; switch (ios_error_code) { @@ -40,7 +45,13 @@ *net_error_code = net::ERR_CONNECTION_TIMED_OUT; break; case kCFURLErrorUnsupportedURL: - *net_error_code = net::ERR_UNKNOWN_URL_SCHEME; + if (GetWebClient()->IsAppSpecificURL(net::GURLWithNSURL(url))) { + // Scheme is valid, but URL is not supported. + *net_error_code = net::ERR_INVALID_URL; + } else { + // Scheme is not app-specific and not supported by WebState. + *net_error_code = net::ERR_UNKNOWN_URL_SCHEME; + } break; case kCFURLErrorCannotFindHost: *net_error_code = net::ERR_NAME_NOT_RESOLVED; @@ -154,7 +165,9 @@ isEqualToString:static_cast<NSString*>(kCFErrorDomainCFNetwork)]) { // Attempt to translate NSURL and CFNetwork error codes into their // corresponding net error codes. - GetNetErrorFromIOSErrorCode(underlying_error.code, &net_error_code); + NSString* url_spec = error.userInfo[NSURLErrorFailingURLStringErrorKey]; + NSURL* url = url_spec ? [NSURL URLWithString:url_spec] : nil; + GetNetErrorFromIOSErrorCode(underlying_error.code, &net_error_code, url); } return NetErrorFromError(error, net_error_code); }
diff --git a/ios/web/web_state/error_translation_util_unittest.mm b/ios/web/web_state/error_translation_util_unittest.mm index 45167fa4..ee150b3 100644 --- a/ios/web/web_state/error_translation_util_unittest.mm +++ b/ios/web/web_state/error_translation_util_unittest.mm
@@ -8,10 +8,14 @@ #include "base/mac/foundation_util.h" #import "ios/net/protocol_handler_util.h" +#include "ios/web/test/test_url_constants.h" +#import "net/base/mac/url_conversions.h" #include "net/base/net_errors.h" #include "testing/gtest/include/gtest/gtest.h" #import "testing/gtest_mac.h" #include "testing/platform_test.h" +#include "url/gurl.h" +#include "url/scheme_host_port.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -24,12 +28,29 @@ // Tests translation of CFNetwork error code to net error code. TEST_F(ErrorTranslationUtilTest, ErrorCodeTranslation) { + // kCFURLErrorUnknown -> net::ERR_FAILED int net_error_code = 0; - EXPECT_TRUE(GetNetErrorFromIOSErrorCode(kCFURLErrorUnknown, &net_error_code)); + EXPECT_TRUE(GetNetErrorFromIOSErrorCode(kCFURLErrorUnknown, &net_error_code, + /*url=*/nil)); EXPECT_EQ(net::ERR_FAILED, net_error_code); + // kCFURLErrorUnsupportedURL -> net::ERR_INVALID_URL for app specific URLs. + GURL web_ui_url(url::SchemeHostPort(kTestWebUIScheme, "foo", 0).Serialize()); + EXPECT_TRUE(GetNetErrorFromIOSErrorCode(kCFURLErrorUnsupportedURL, + &net_error_code, + net::NSURLWithGURL(web_ui_url))); + EXPECT_EQ(net::ERR_INVALID_URL, net_error_code); + + // kCFURLErrorUnsupportedURL -> net::ERR_UNKNOWN_URL_SCHEME for app with + // scheme that is neither supported by WebState nor app-specific scheme. + NSURL* unsupported_url = [NSURL URLWithString:@"fooooo:baaar"]; + EXPECT_TRUE(GetNetErrorFromIOSErrorCode(kCFURLErrorUnsupportedURL, + &net_error_code, unsupported_url)); + EXPECT_EQ(net::ERR_UNKNOWN_URL_SCHEME, net_error_code); + + // kCFSOCKSErrorUnknownClientVersion -> ? EXPECT_FALSE(GetNetErrorFromIOSErrorCode(kCFSOCKSErrorUnknownClientVersion, - &net_error_code)); + &net_error_code, /*url=*/nil)); } // Tests translation of an error with empty domain and no underlying error.
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 859ff648..be5d2a0 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -4476,6 +4476,15 @@ if (allowNavigation) { allowNavigation = self.webStateImpl->ShouldAllowResponse( navigationResponse.response, navigationResponse.forMainFrame); + if (allowNavigation && responseURL.SchemeIs(url::kDataScheme) && + navigationResponse.forMainFrame) { + // Block rendering data URLs for renderer-initiated navigations in main + // frame to prevent abusive behavior (crbug.com/890558). Data URLs + // downloads are still allowed. + web::NavigationContextImpl* context = + [self contextForPendingMainFrameNavigationWithURL:responseURL]; + allowNavigation = !context->IsRendererInitiated(); + } if (!allowNavigation && navigationResponse.isForMainFrame) { [_pendingNavigationInfo setCancelled:YES]; }
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index a28a4cc..7491c4a 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -79,6 +79,8 @@ // Syntactically invalid URL per rfc3986. const char kInvalidURL[] = "http://%3"; +const char kTestDataURL[] = "data:text/html,"; + const char kTestURLString[] = "http://www.google.com/"; const char kTestAppSpecificURL[] = "testwebui://test/"; @@ -658,22 +660,25 @@ INSTANTIATE_TEST_CASES(CRWWebControllerJSExecutionTest); -// Test fixture to test that DownloadControllerDelegate::OnDownloadCreated -// callback is trigerred if CRWWebController can not display the response. -class CRWWebControllerDownloadTest : public CRWWebControllerTest { +// Test fixture to test decidePolicyForNavigationResponse:decisionHandler: +// delegate method. +class CRWWebControllerResponseTest : public CRWWebControllerTest { protected: - CRWWebControllerDownloadTest() : delegate_(download_controller()) {} + CRWWebControllerResponseTest() : download_delegate_(download_controller()) {} // Calls webView:decidePolicyForNavigationResponse:decisionHandler: callback // and waits for decision handler call. Returns false if decision handler call // times out. bool CallDecidePolicyForNavigationResponseWithResponse( NSURLResponse* response, - BOOL for_main_frame) WARN_UNUSED_RESULT { + BOOL for_main_frame, + BOOL can_show_mime_type, + WKNavigationResponsePolicy* out_policy) WARN_UNUSED_RESULT { CRWFakeWKNavigationResponse* navigation_response = [[CRWFakeWKNavigationResponse alloc] init]; navigation_response.response = response; navigation_response.forMainFrame = for_main_frame; + navigation_response.canShowMIMEType = can_show_mime_type; // Call decidePolicyForNavigationResponse and wait for decisionHandler's // callback. @@ -686,6 +691,7 @@ [navigation_delegate_ webView:mock_web_view_ decidePolicyForNavigationResponse:navigation_response decisionHandler:^(WKNavigationResponsePolicy policy) { + *out_policy = policy; callback_called = true; }]; return WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ @@ -697,12 +703,93 @@ return DownloadController::FromBrowserState(GetBrowserState()); } - FakeDownloadControllerDelegate delegate_; + FakeDownloadControllerDelegate download_delegate_; }; +// Tests that webView:decidePolicyForNavigationResponse:decisionHandler: allows +// renderer-initiated navigations in main frame for http: URLs. +TEST_P(CRWWebControllerResponseTest, AllowRendererInitiatedResponse) { + // Simulate regular navigation response with text/html MIME type. + NSURLResponse* response = [[NSHTTPURLResponse alloc] + initWithURL:[NSURL URLWithString:@(kTestURLString)] + statusCode:200 + HTTPVersion:nil + headerFields:nil]; + WKNavigationResponsePolicy policy = WKNavigationResponsePolicyCancel; + ASSERT_TRUE(CallDecidePolicyForNavigationResponseWithResponse( + response, /*for_main_frame=*/YES, /*can_show_mime_type=*/YES, &policy)); + EXPECT_EQ(WKNavigationResponsePolicyAllow, policy); + + // Verify that download task was not created for html response. + ASSERT_TRUE(download_delegate_.alive_download_tasks().empty()); +} + +// Tests that webView:decidePolicyForNavigationResponse:decisionHandler: allows +// renderer-initiated navigations in iframe for data: URLs. +TEST_P(CRWWebControllerResponseTest, + AllowRendererInitiatedDataUrlResponseInIFrame) { + // Simulate data:// url response with text/html MIME type. + SetWebViewURL(@(kTestDataURL)); + NSURLResponse* response = [[NSHTTPURLResponse alloc] + initWithURL:[NSURL URLWithString:@(kTestDataURL)] + statusCode:200 + HTTPVersion:nil + headerFields:nil]; + WKNavigationResponsePolicy policy = WKNavigationResponsePolicyCancel; + ASSERT_TRUE(CallDecidePolicyForNavigationResponseWithResponse( + response, /*for_main_frame=*/NO, /*can_show_mime_type=*/YES, &policy)); + EXPECT_EQ(WKNavigationResponsePolicyAllow, policy); + + // Verify that download task was not created for html response. + ASSERT_TRUE(download_delegate_.alive_download_tasks().empty()); +} + +// Tests that webView:decidePolicyForNavigationResponse:decisionHandler: blocks +// rendering data URLs for renderer-initiated navigations in main frame to +// prevent abusive behavior (crbug.com/890558). +TEST_P(CRWWebControllerResponseTest, + BlockRendererInitiatedDataUrlResponseInMainFrame) { + // Simulate data:// url response with text/html MIME type. + SetWebViewURL(@(kTestDataURL)); + NSURLResponse* response = [[NSHTTPURLResponse alloc] + initWithURL:[NSURL URLWithString:@(kTestDataURL)] + statusCode:200 + HTTPVersion:nil + headerFields:nil]; + WKNavigationResponsePolicy policy = WKNavigationResponsePolicyAllow; + ASSERT_TRUE(CallDecidePolicyForNavigationResponseWithResponse( + response, /*for_main_frame=*/YES, /*can_show_mime_type=*/YES, &policy)); + EXPECT_EQ(WKNavigationResponsePolicyCancel, policy); + + // Verify that download task was not created for html response. + ASSERT_TRUE(download_delegate_.alive_download_tasks().empty()); +} + +// Tests that webView:decidePolicyForNavigationResponse:decisionHandler: allows +// rendering data URLs for browser-initiated navigations in main frame. +TEST_P(CRWWebControllerResponseTest, + AllowBrowserInitiatedDataUrlResponseInMainFrame) { + // Simulate data:// url response with text/html MIME type. + GURL url(kTestDataURL); + AddPendingItem(url, ui::PAGE_TRANSITION_TYPED); + SetWebViewURL(@(kTestDataURL)); + NSURLResponse* response = [[NSHTTPURLResponse alloc] + initWithURL:[NSURL URLWithString:@(kTestDataURL)] + statusCode:200 + HTTPVersion:nil + headerFields:nil]; + WKNavigationResponsePolicy policy = WKNavigationResponsePolicyCancel; + ASSERT_TRUE(CallDecidePolicyForNavigationResponseWithResponse( + response, /*for_main_frame=*/YES, /*can_show_mime_type=*/YES, &policy)); + EXPECT_EQ(WKNavigationResponsePolicyAllow, policy); + + // Verify that download task was not created for html response. + ASSERT_TRUE(download_delegate_.alive_download_tasks().empty()); +} + // Tests that webView:decidePolicyForNavigationResponse:decisionHandler: creates // the DownloadTask for NSURLResponse. -TEST_P(CRWWebControllerDownloadTest, CreationWithNSURLResponse) { +TEST_P(CRWWebControllerResponseTest, DownloadWithNSURLResponse) { // Simulate download response. int64_t content_length = 10; NSURLResponse* response = @@ -710,12 +797,15 @@ MIMEType:@(kTestMimeType) expectedContentLength:content_length textEncodingName:nil]; + WKNavigationResponsePolicy policy = WKNavigationResponsePolicyAllow; ASSERT_TRUE(CallDecidePolicyForNavigationResponseWithResponse( - response, /*for_main_frame=*/YES)); + response, /*for_main_frame=*/YES, /*can_show_mime_type=*/NO, &policy)); + EXPECT_EQ(WKNavigationResponsePolicyCancel, policy); // Verify that download task was created. - ASSERT_EQ(1U, delegate_.alive_download_tasks().size()); - DownloadTask* task = delegate_.alive_download_tasks()[0].second.get(); + ASSERT_EQ(1U, download_delegate_.alive_download_tasks().size()); + DownloadTask* task = + download_delegate_.alive_download_tasks()[0].second.get(); ASSERT_TRUE(task); EXPECT_TRUE(task->GetIndentifier()); EXPECT_EQ(kTestURLString, task->GetOriginalUrl()); @@ -729,7 +819,7 @@ // Tests that webView:decidePolicyForNavigationResponse:decisionHandler: creates // the DownloadTask for NSHTTPURLResponse. -TEST_P(CRWWebControllerDownloadTest, CreationWithNSHTTPURLResponse) { +TEST_P(CRWWebControllerResponseTest, DownloadWithNSHTTPURLResponse) { // Simulate download response. const char kContentDisposition[] = "attachment; filename=download.test"; NSURLResponse* response = [[NSHTTPURLResponse alloc] @@ -739,12 +829,15 @@ headerFields:@{ @"content-disposition" : @(kContentDisposition), }]; + WKNavigationResponsePolicy policy = WKNavigationResponsePolicyAllow; ASSERT_TRUE(CallDecidePolicyForNavigationResponseWithResponse( - response, /*for_main_frame=*/YES)); + response, /*for_main_frame=*/YES, /*can_show_mime_type=*/NO, &policy)); + EXPECT_EQ(WKNavigationResponsePolicyCancel, policy); // Verify that download task was created. - ASSERT_EQ(1U, delegate_.alive_download_tasks().size()); - DownloadTask* task = delegate_.alive_download_tasks()[0].second.get(); + ASSERT_EQ(1U, download_delegate_.alive_download_tasks().size()); + DownloadTask* task = + download_delegate_.alive_download_tasks()[0].second.get(); ASSERT_TRUE(task); EXPECT_TRUE(task->GetIndentifier()); EXPECT_EQ(kTestURLString, task->GetOriginalUrl()); @@ -758,7 +851,7 @@ // Tests that webView:decidePolicyForNavigationResponse:decisionHandler: creates // the DownloadTask for NSHTTPURLResponse and iframes. -TEST_P(CRWWebControllerDownloadTest, IFrameCreationWithNSHTTPURLResponse) { +TEST_P(CRWWebControllerResponseTest, IFrameDownloadWithNSHTTPURLResponse) { // Simulate download response. const char kContentDisposition[] = "attachment; filename=download.test"; NSURLResponse* response = [[NSHTTPURLResponse alloc] @@ -768,12 +861,15 @@ headerFields:@{ @"content-disposition" : @(kContentDisposition), }]; + WKNavigationResponsePolicy policy = WKNavigationResponsePolicyAllow; ASSERT_TRUE(CallDecidePolicyForNavigationResponseWithResponse( - response, /*for_main_frame=*/NO)); + response, /*for_main_frame=*/NO, /*can_show_mime_type=*/NO, &policy)); + EXPECT_EQ(WKNavigationResponsePolicyCancel, policy); // Verify that download task was created. - ASSERT_EQ(1U, delegate_.alive_download_tasks().size()); - DownloadTask* task = delegate_.alive_download_tasks()[0].second.get(); + ASSERT_EQ(1U, download_delegate_.alive_download_tasks().size()); + DownloadTask* task = + download_delegate_.alive_download_tasks()[0].second.get(); ASSERT_TRUE(task); EXPECT_TRUE(task->GetIndentifier()); EXPECT_EQ(kTestURLString, task->GetOriginalUrl()); @@ -809,7 +905,7 @@ EXPECT_EQ(kAbsolute, trust_level); } -INSTANTIATE_TEST_CASES(CRWWebControllerDownloadTest); +INSTANTIATE_TEST_CASES(CRWWebControllerResponseTest); // Test fixture to test decidePolicyForNavigationAction:decisionHandler: // decisionHandler's callback result.
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h index a408c013..4c4c1111 100644 --- a/ipc/ipc_message_start.h +++ b/ipc/ipc_message_start.h
@@ -68,6 +68,7 @@ SurfaceViewManagerMsgStart, ExtensionWorkerMsgStart, SubresourceFilterMsgStart, + ChromeAppsMsgStart, LastIPCMsgStart // Must come last. };
diff --git a/media/capture/ipc/BUILD.gn b/media/capture/ipc/BUILD.gn deleted file mode 100644 index dc78b719..0000000 --- a/media/capture/ipc/BUILD.gn +++ /dev/null
@@ -1,24 +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. - -source_set("ipc") { - sources = [ - "capture_param_traits.cc", - "capture_param_traits.h", - "capture_param_traits_macros.h", - ] - - public_deps = [ - "//ipc", - ] - deps = [ - "//base", - "//media", - "//media/base/ipc", - "//media/capture:capture_base", - "//ui/gfx/ipc", - "//ui/gfx/ipc/geometry", - "//ui/gfx/ipc/skia", - ] -}
diff --git a/media/capture/ipc/DEPS b/media/capture/ipc/DEPS deleted file mode 100644 index edcceac..0000000 --- a/media/capture/ipc/DEPS +++ /dev/null
@@ -1,4 +0,0 @@ -include_rules = [ - "+ipc", - "-media/capture/capture_export.h", -]
diff --git a/media/capture/ipc/OWNERS b/media/capture/ipc/OWNERS deleted file mode 100644 index 146c3c3c..0000000 --- a/media/capture/ipc/OWNERS +++ /dev/null
@@ -1,2 +0,0 @@ -per-file *_param_traits*.*=set noparent -per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/media/capture/ipc/capture_param_traits.cc b/media/capture/ipc/capture_param_traits.cc deleted file mode 100644 index b55e80f..0000000 --- a/media/capture/ipc/capture_param_traits.cc +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/capture/ipc/capture_param_traits.h" - -#include "base/strings/stringprintf.h" -#include "ipc/ipc_message_utils.h" -#include "media/base/ipc/media_param_traits.h" -#include "media/base/limits.h" -#include "media/capture/video_capture_types.h" -#include "ui/gfx/ipc/geometry/gfx_param_traits.h" -#include "ui/gfx/ipc/gfx_param_traits.h" -#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" - -using media::VideoCaptureFormat; - -namespace IPC { - -void ParamTraits<VideoCaptureFormat>::Write(base::Pickle* m, - const VideoCaptureFormat& p) { - WriteParam(m, p.frame_size); - WriteParam(m, p.frame_rate); - WriteParam(m, p.pixel_format); -} - -bool ParamTraits<VideoCaptureFormat>::Read(const base::Pickle* m, - base::PickleIterator* iter, - VideoCaptureFormat* r) { - if (!ReadParam(m, iter, &r->frame_size) || - !ReadParam(m, iter, &r->frame_rate) || - !ReadParam(m, iter, &r->pixel_format)) { - return false; - } - return r->IsValid(); -} - -void ParamTraits<VideoCaptureFormat>::Log(const VideoCaptureFormat& p, - std::string* l) { - l->append(base::StringPrintf("<VideoCaptureFormat> %s", - media::VideoCaptureFormat::ToString(p).c_str())); -} - -} // namespace IPC - -// Generate param traits write methods. -#include "ipc/param_traits_write_macros.h" -namespace IPC { -#undef MEDIA_CAPTURE_IPC_CAPTURE_PARAM_TRAITS_MACROS_H_ -#include "media/capture/ipc/capture_param_traits_macros.h" -} // namespace IPC - -// Generate param traits read methods. -#include "ipc/param_traits_read_macros.h" -namespace IPC { -#undef MEDIA_CAPTURE_IPC_CAPTURE_PARAM_TRAITS_MACROS_H_ -#include "media/capture/ipc/capture_param_traits_macros.h" -} // namespace IPC - -// Generate param traits log methods. -#include "ipc/param_traits_log_macros.h" -namespace IPC { -#undef MEDIA_CAPTURE_IPC_CAPTURE_PARAM_TRAITS_MACROS_H_ -#include "media/capture/ipc/capture_param_traits_macros.h" -} // namespace IPC
diff --git a/media/capture/ipc/capture_param_traits.h b/media/capture/ipc/capture_param_traits.h deleted file mode 100644 index 5a49960..0000000 --- a/media/capture/ipc/capture_param_traits.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_CAPTURE_IPC_CAPTURE_PARAM_TRAITS_H_ -#define MEDIA_CAPTURE_IPC_CAPTURE_PARAM_TRAITS_H_ - -#include "ipc/ipc_message.h" -#include "ipc/ipc_param_traits.h" -#include "media/capture/ipc/capture_param_traits_macros.h" - -namespace media { -struct VideoCaptureFormat; -} - -namespace IPC { - -template <> -struct ParamTraits<media::VideoCaptureFormat> { - typedef media::VideoCaptureFormat param_type; - static void Write(base::Pickle* m, const param_type& p); - static bool Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* r); - static void Log(const param_type& p, std::string* l); -}; - -} // namespace IPC - -#endif // MEDIA_CAPTURE_IPC_CAPTURE_PARAM_TRAITS_H_
diff --git a/media/capture/ipc/capture_param_traits_macros.h b/media/capture/ipc/capture_param_traits_macros.h deleted file mode 100644 index 30d8f93..0000000 --- a/media/capture/ipc/capture_param_traits_macros.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_CAPTURE_IPC_CAPTURE_PARAM_TRAITS_MACROS_H_ -#define MEDIA_CAPTURE_IPC_CAPTURE_PARAM_TRAITS_MACROS_H_ - -#include "ipc/ipc_message_macros.h" -#include "media/capture/video/video_capture_device_descriptor.h" -#include "media/capture/video_capture_types.h" - -IPC_STRUCT_TRAITS_BEGIN(media::VideoCaptureDeviceDescriptor::CameraCalibration) - IPC_STRUCT_TRAITS_MEMBER(focal_length_x) - IPC_STRUCT_TRAITS_MEMBER(focal_length_y) - IPC_STRUCT_TRAITS_MEMBER(depth_near) - IPC_STRUCT_TRAITS_MEMBER(depth_far) -IPC_STRUCT_TRAITS_END() - -#endif // MEDIA_CAPTURE_IPC_CAPTURE_PARAM_TRAITS_MACROS_H_
diff --git a/media/capture/mojom/video_capture_types.typemap b/media/capture/mojom/video_capture_types.typemap index e54002d..146a77b 100644 --- a/media/capture/mojom/video_capture_types.typemap +++ b/media/capture/mojom/video_capture_types.typemap
@@ -10,11 +10,7 @@ "//media/capture/video/video_capture_device_info.h", ] -traits_headers = [ - "//media/capture/ipc/capture_param_traits_macros.h", - "//media/capture/ipc/capture_param_traits.h", - "//media/capture/mojom/video_capture_types_mojom_traits.h", -] +traits_headers = [ "//media/capture/mojom/video_capture_types_mojom_traits.h" ] sources = [ "//media/capture/mojom/video_capture_types_mojom_traits.cc", @@ -24,7 +20,6 @@ "//media", "//media/base/ipc", "//media/capture:capture_base", - "//media/capture/ipc", "//media/mojo/interfaces", "//ui/gfx/geometry/mojo:struct_traits", ]
diff --git a/media/formats/webm/webm_tracks_parser.cc b/media/formats/webm/webm_tracks_parser.cc index 2379ac5..e3941ae 100644 --- a/media/formats/webm/webm_tracks_parser.cc +++ b/media/formats/webm/webm_tracks_parser.cc
@@ -116,7 +116,11 @@ WebMParserClient* WebMTracksParser::OnListStart(int id) { if (id == kWebMIdContentEncodings) { - DCHECK(!track_content_encodings_client_.get()); + if (track_content_encodings_client_) { + MEDIA_LOG(ERROR, media_log_) << "Multiple ContentEncodings lists"; + return NULL; + } + track_content_encodings_client_.reset( new WebMContentEncodingsClient(media_log_)); return track_content_encodings_client_->OnListStart(id);
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc index 8c3d681..5cb08e3 100644 --- a/media/gpu/windows/d3d11_video_decoder.cc +++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -94,6 +94,9 @@ impl_.reset(); else impl_task_runner_->DeleteSoon(FROM_HERE, std::move(impl_)); + + // Explicitly destroy the decoder, since it can reference picture buffers. + accelerated_video_decoder_.reset(); } std::string D3D11VideoDecoder::GetDisplayName() const {
diff --git a/mojo/public/cpp/system/data_pipe.h b/mojo/public/cpp/system/data_pipe.h index 8e1e0b88..cc789df 100644 --- a/mojo/public/cpp/system/data_pipe.h +++ b/mojo/public/cpp/system/data_pipe.h
@@ -149,7 +149,6 @@ inline DataPipe::DataPipe() { MojoResult result = CreateDataPipe(nullptr, &producer_handle, &consumer_handle); - ALLOW_UNUSED_LOCAL(result); CHECK_EQ(MOJO_RESULT_OK, result); } @@ -159,17 +158,14 @@ options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE; options.element_num_bytes = 1; options.capacity_num_bytes = capacity_num_bytes; - mojo::DataPipe data_pipe(options); MojoResult result = CreateDataPipe(&options, &producer_handle, &consumer_handle); - ALLOW_UNUSED_LOCAL(result); CHECK_EQ(MOJO_RESULT_OK, result); } inline DataPipe::DataPipe(const MojoCreateDataPipeOptions& options) { MojoResult result = CreateDataPipe(&options, &producer_handle, &consumer_handle); - ALLOW_UNUSED_LOCAL(result); CHECK_EQ(MOJO_RESULT_OK, result); }
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn index 0c03953..4a6503c 100644 --- a/net/dns/BUILD.gn +++ b/net/dns/BUILD.gn
@@ -528,6 +528,18 @@ dict = "//net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict" } +fuzzer_test("net_dns_response_fuzzer") { + sources = [ + "dns_response_fuzzer.cc", + ] + deps = [ + "//base", + "//net", + "//net:net_fuzzer_test_support", + ] + dict = "//net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict" +} + fuzzer_test("net_host_resolver_impl_fuzzer") { sources = [ "host_resolver_impl_fuzzer.cc",
diff --git a/net/dns/dns_query.h b/net/dns/dns_query.h index c01909e..8e77ac5 100644 --- a/net/dns/dns_query.h +++ b/net/dns/dns_query.h
@@ -65,6 +65,12 @@ // response. base::StringPiece question() const; + // Returns the size of the question section. + size_t question_size() const { + // QNAME + QTYPE + QCLASS + return qname_size_ + sizeof(uint16_t) + sizeof(uint16_t); + } + // IOBuffer accessor to be used for writing out the query. The buffer has // the same byte layout as the DNS query wire format. IOBufferWithSize* io_buffer() const { return io_buffer_.get(); } @@ -80,12 +86,6 @@ // convert to the dotted format "www.chromium.com" with no trailing dot. bool ReadName(base::BigEndianReader* reader, std::string* out); - // Returns the size of the question section. - size_t question_size() const { - // QNAME + QTYPE + QCLASS - return qname_size_ + sizeof(uint16_t) + sizeof(uint16_t); - } - // Size of the DNS name (*NOT* hostname) we are trying to resolve; used // to calculate offsets. size_t qname_size_ = 0;
diff --git a/net/dns/dns_query_parse_fuzzer.cc b/net/dns/dns_query_parse_fuzzer.cc index dceb703..f936218 100644 --- a/net/dns/dns_query_parse_fuzzer.cc +++ b/net/dns/dns_query_parse_fuzzer.cc
@@ -14,7 +14,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { auto packet = base::MakeRefCounted<net::IOBufferWithSize>(size); memcpy(packet->data(), data, size); - auto out = std::make_unique<net::DnsQuery>(packet.get()); + auto out = std::make_unique<net::DnsQuery>(packet); out->Parse(); return 0; }
diff --git a/net/dns/dns_response.cc b/net/dns/dns_response.cc index 809ca0fb6..7177dcaf 100644 --- a/net/dns/dns_response.cc +++ b/net/dns/dns_response.cc
@@ -159,10 +159,12 @@ return true; } -DnsResponse::DnsResponse(uint16_t id, - bool is_authoritative, - const std::vector<DnsResourceRecord>& answers, - const base::Optional<DnsQuery>& query) { +DnsResponse::DnsResponse( + uint16_t id, + bool is_authoritative, + const std::vector<DnsResourceRecord>& answers, + const std::vector<DnsResourceRecord>& additional_records, + const base::Optional<DnsQuery>& query) { bool has_query = query.has_value(); dns_protocol::Header header; header.id = id; @@ -178,23 +180,28 @@ header.flags |= dns_protocol::kFlagAA; } header.ancount = answers.size(); + header.arcount = additional_records.size(); // Response starts with the header and the question section (if any). - size_t response_size = - has_query ? query.value().io_buffer()->size() : sizeof(header); - // Add the size of all answers. - response_size = std::accumulate( - answers.begin(), answers.end(), response_size, - [](size_t cur_size, const DnsResourceRecord& answer) { - bool has_final_dot = answer.name.back() == '.'; - // Depending on if answer.name in the dotted format has the final dot - // for the root domain or not, the corresponding DNS domain name format - // to be written to rdata is 1 byte (with dot) or 2 bytes larger in - // size. See RFC 1035, Section 3.1 and DNSDomainFromDot. - return cur_size + answer.name.size() + (has_final_dot ? 1 : 2) + - kResourceRecordSizeInBytesWithoutNameAndRData + - answer.rdata.size(); - }); + size_t response_size = has_query + ? sizeof(header) + query.value().question_size() + : sizeof(header); + // Add the size of all answers and additional records. + auto do_accumulation = [](size_t cur_size, const DnsResourceRecord& answer) { + bool has_final_dot = answer.name.back() == '.'; + // Depending on if answer.name in the dotted format has the final dot + // for the root domain or not, the corresponding DNS domain name format + // to be written to rdata is 1 byte (with dot) or 2 bytes larger in + // size. See RFC 1035, Section 3.1 and DNSDomainFromDot. + return cur_size + answer.name.size() + (has_final_dot ? 1 : 2) + + kResourceRecordSizeInBytesWithoutNameAndRData + answer.rdata.size(); + }; + response_size = std::accumulate(answers.begin(), answers.end(), response_size, + do_accumulation); + + response_size = + std::accumulate(additional_records.begin(), additional_records.end(), + response_size, do_accumulation); io_buffer_ = base::MakeRefCounted<IOBuffer>(response_size); io_buffer_size_ = response_size; @@ -205,10 +212,16 @@ success &= WriteQuestion(&writer, query.value()); DCHECK(success); } + // Start the Answer section. for (const auto& answer : answers) { success &= WriteAnswer(&writer, answer, query); DCHECK(success); } + // Start the Additional section. + for (const auto& record : additional_records) { + success &= WriteRecord(&writer, record); + DCHECK(success); + } if (!success) { io_buffer_.reset(); io_buffer_size_ = 0; @@ -434,6 +447,24 @@ return writer->WriteBytes(question.data(), question.size()); } +bool DnsResponse::WriteRecord(base::BigEndianWriter* writer, + const DnsResourceRecord& record) { + if (!RecordRdata::HasValidSize(record.rdata, record.type)) { + VLOG(1) << "Invalid RDATA size for a record."; + return false; + } + std::string domain_name; + if (!DNSDomainFromDot(record.name, &domain_name)) { + VLOG(1) << "Invalid dotted name."; + return false; + } + return writer->WriteBytes(domain_name.data(), domain_name.size()) && + writer->WriteU16(record.type) && writer->WriteU16(record.klass) && + writer->WriteU32(record.ttl) && + writer->WriteU16(record.rdata.size()) && + writer->WriteBytes(record.rdata.data(), record.rdata.size()); +} + bool DnsResponse::WriteAnswer(base::BigEndianWriter* writer, const DnsResourceRecord& answer, const base::Optional<DnsQuery>& query) { @@ -441,20 +472,7 @@ VLOG(1) << "Mismatched answer resource record type and qtype."; return false; } - if (!RecordRdata::HasValidSize(answer.rdata, answer.type)) { - VLOG(1) << "Invalid RDATA size for an answer."; - return false; - } - std::string domain_name; - if (!DNSDomainFromDot(answer.name, &domain_name)) { - VLOG(1) << "Invalid dotted name."; - return false; - } - return writer->WriteBytes(domain_name.data(), domain_name.size()) && - writer->WriteU16(answer.type) && writer->WriteU16(answer.klass) && - writer->WriteU32(answer.ttl) && - writer->WriteU16(answer.rdata.size()) && - writer->WriteBytes(answer.rdata.data(), answer.rdata.size()); + return WriteRecord(writer, answer); } } // namespace net
diff --git a/net/dns/dns_response.h b/net/dns/dns_response.h index 1f8aefbf..c796295 100644 --- a/net/dns/dns_response.h +++ b/net/dns/dns_response.h
@@ -116,6 +116,7 @@ DnsResponse(uint16_t id, bool is_authoritative, const std::vector<DnsResourceRecord>& answers, + const std::vector<DnsResourceRecord>& additional_records, const base::Optional<DnsQuery>& query); // Constructs a response buffer of given length. Used for TCP transactions. @@ -179,6 +180,8 @@ bool WriteHeader(base::BigEndianWriter* writer, const dns_protocol::Header& header); bool WriteQuestion(base::BigEndianWriter* writer, const DnsQuery& query); + bool WriteRecord(base::BigEndianWriter* wirter, + const DnsResourceRecord& record); bool WriteAnswer(base::BigEndianWriter* wirter, const DnsResourceRecord& answer, const base::Optional<DnsQuery>& query);
diff --git a/net/dns/dns_response_fuzzer.cc b/net/dns/dns_response_fuzzer.cc new file mode 100644 index 0000000..c53e179a --- /dev/null +++ b/net/dns/dns_response_fuzzer.cc
@@ -0,0 +1,30 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stddef.h> +#include <stdint.h> + +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "net/base/io_buffer.h" +#include "net/dns/dns_protocol.h" +#include "net/dns/dns_query.h" +#include "net/dns/dns_response.h" + +// Entry point for LibFuzzer. +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + auto packet = base::MakeRefCounted<net::IOBufferWithSize>(size); + memcpy(packet->data(), data, size); + base::Optional<net::DnsQuery> query; + query.emplace(packet); + if (!query->Parse()) { + return 0; + } + net::DnsResponse response(query->id(), true /* is_authoritative */, + {} /* answers */, {} /* additional records */, + query); + std::string out = + base::HexEncode(response.io_buffer()->data(), response.io_buffer_size()); + return 0; +}
diff --git a/net/dns/dns_response_unittest.cc b/net/dns/dns_response_unittest.cc index 163f28c..7ec9410d 100644 --- a/net/dns/dns_response_unittest.cc +++ b/net/dns/dns_response_unittest.cc
@@ -4,6 +4,7 @@ #include "net/dns/dns_response.h" +#include "base/big_endian.h" #include "base/optional.h" #include "base/time/time.h" #include "net/base/address_list.h" @@ -12,6 +13,7 @@ #include "net/dns/dns_query.h" #include "net/dns/dns_test_util.h" #include "net/dns/dns_util.h" +#include "net/dns/record_rdata.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -596,7 +598,7 @@ answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4); std::vector<DnsResourceRecord> answers(1, answer); DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/, - answers, base::nullopt); + answers, {} /* additional records */, base::nullopt); ASSERT_NE(nullptr, response.io_buffer()); EXPECT_TRUE(response.IsValid()); std::string expected_response(response_data, sizeof(response_data)); @@ -630,7 +632,7 @@ answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4); std::vector<DnsResourceRecord> answers(1, answer); DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/, - answers, base::nullopt); + answers, {} /* additional records */, base::nullopt); ASSERT_NE(nullptr, response.io_buffer()); EXPECT_TRUE(response.IsValid()); std::string expected_response(response_data, sizeof(response_data)); @@ -664,8 +666,10 @@ std::string dotted_name("www.example.com"); std::string dns_name; ASSERT_TRUE(DNSDomainFromDot(dotted_name, &dns_name)); + OptRecordRdata opt_rdata; + opt_rdata.AddOpt(OptRecordRdata::Opt(255, "\xde\xad\xbe\xef")); base::Optional<DnsQuery> query; - query.emplace(0x1234 /* id */, dns_name, dns_protocol::kTypeA); + query.emplace(0x1234 /* id */, dns_name, dns_protocol::kTypeA, &opt_rdata); net::DnsResourceRecord answer; answer.name = dotted_name; answer.type = dns_protocol::kTypeA; @@ -674,7 +678,70 @@ answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4); std::vector<DnsResourceRecord> answers(1, answer); DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers, - query); + {} /* additional records */, query); + ASSERT_NE(nullptr, response.io_buffer()); + EXPECT_TRUE(response.IsValid()); + std::string expected_response(response_data, sizeof(response_data)); + std::string actual_response(response.io_buffer()->data(), + response.io_buffer_size()); + EXPECT_EQ(expected_response, actual_response); +} + +TEST(DnsResponseWriteTest, + SingleAnswerWithQuestionConstructedFromSizeInflatedQuery) { + const char response_data[] = { + 0x12, 0x34, // ID + 0x84, 0x00, // flags, response with authoritative answer + 0x00, 0x01, // number of questions + 0x00, 0x01, // number of answer rr + 0x00, 0x00, // number of name server rr + 0x00, 0x00, // number of additional rr + 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', + 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', + 0x00, // null label + 0x00, 0x01, // type A Record + 0x00, 0x01, // class IN + 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', + 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', + 0x00, // null label + 0x00, 0x01, // type A Record + 0x00, 0x01, // class IN + 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds + 0x00, 0x04, // rdlength, 32 bits + 0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1 + }; + std::string dotted_name("www.example.com"); + std::string dns_name; + ASSERT_TRUE(DNSDomainFromDot(dotted_name, &dns_name)); + size_t buf_size = + sizeof(dns_protocol::Header) + dns_name.size() + 2 /* qtype */ + + 2 /* qclass */ + + 10 /* extra bytes that inflate the internal buffer of a query */; + auto buf = base::MakeRefCounted<IOBufferWithSize>(buf_size); + memset(buf->data(), 0, buf->size()); + base::BigEndianWriter writer(buf->data(), buf_size); + writer.WriteU16(0x1234); // id + writer.WriteU16(0); // flags, is query + writer.WriteU16(1); // qdcount + writer.WriteU16(0); // ancount + writer.WriteU16(0); // nscount + writer.WriteU16(0); // arcount + writer.WriteBytes(dns_name.data(), dns_name.size()); // qname + writer.WriteU16(dns_protocol::kTypeA); // qtype + writer.WriteU16(dns_protocol::kClassIN); // qclass + // buf contains 10 extra zero bytes. + base::Optional<DnsQuery> query; + query.emplace(buf); + query->Parse(); + net::DnsResourceRecord answer; + answer.name = dotted_name; + answer.type = dns_protocol::kTypeA; + answer.klass = dns_protocol::kClassIN; + answer.ttl = 120; // 120 seconds. + answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4); + std::vector<DnsResourceRecord> answers(1, answer); + DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers, + {} /* additional records */, query); ASSERT_NE(nullptr, response.io_buffer()); EXPECT_TRUE(response.IsValid()); std::string expected_response(response_data, sizeof(response_data)); @@ -710,7 +777,70 @@ "\xfd\x12\x34\x56\x78\x9a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01", 16); std::vector<DnsResourceRecord> answers(1, answer); DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers, - base::nullopt); + {} /* additional records */, base::nullopt); + ASSERT_NE(nullptr, response.io_buffer()); + EXPECT_TRUE(response.IsValid()); + std::string expected_response(response_data, sizeof(response_data)); + std::string actual_response(response.io_buffer()->data(), + response.io_buffer_size()); + EXPECT_EQ(expected_response, actual_response); +} + +TEST(DnsResponseWriteTest, + SingleARecordAnswerWithQuestionAndNsecAdditionalRecord) { + const char response_data[] = { + 0x12, 0x34, // ID + 0x84, 0x00, // flags, response with authoritative answer + 0x00, 0x01, // number of questions + 0x00, 0x01, // number of answer rr + 0x00, 0x00, // number of name server rr + 0x00, 0x01, // number of additional rr + 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', + 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', + 0x00, // null label + 0x00, 0x01, // type A Record + 0x00, 0x01, // class IN + 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', + 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', + 0x00, // null label + 0x00, 0x01, // type A Record + 0x00, 0x01, // class IN + 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds + 0x00, 0x04, // rdlength, 32 bits + 0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1 + 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', + 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', + 0x00, // null label + 0x00, 0x2f, // type NSEC Record + 0x00, 0x01, // class IN + 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds + 0x00, 0x05, // rdlength, 5 bytes + 0xc0, 0x0c, // pointer to the previous "www.example.com" + 0x00, 0x01, 0x40, // type bit map of type A: window block 0, bitmap + // length 1, bitmap with bit 1 set + }; + std::string dotted_name("www.example.com"); + std::string dns_name; + ASSERT_TRUE(DNSDomainFromDot(dotted_name, &dns_name)); + base::Optional<DnsQuery> query; + query.emplace(0x1234 /* id */, dns_name, dns_protocol::kTypeA); + net::DnsResourceRecord answer; + answer.name = dotted_name; + answer.type = dns_protocol::kTypeA; + answer.klass = dns_protocol::kClassIN; + answer.ttl = 120; // 120 seconds. + answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4); + std::vector<DnsResourceRecord> answers(1, answer); + net::DnsResourceRecord additional_record; + additional_record.name = dotted_name; + additional_record.type = dns_protocol::kTypeNSEC; + additional_record.klass = dns_protocol::kClassIN; + additional_record.ttl = 120; // 120 seconds. + // Bitmap for "www.example.com" with type A set. + additional_record.rdata = base::StringPiece("\xc0\x0c\x00\x01\x40", 5); + std::vector<DnsResourceRecord> additional_records(1, additional_record); + DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers, + additional_records, query); ASSERT_NE(nullptr, response.io_buffer()); EXPECT_TRUE(response.IsValid()); std::string expected_response(response_data, sizeof(response_data)); @@ -761,7 +891,7 @@ answers[0] = answer1; answers[1] = answer2; DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers, - base::nullopt); + {} /* additional records */, base::nullopt); ASSERT_NE(nullptr, response.io_buffer()); EXPECT_TRUE(response.IsValid()); std::string expected_response(response_data, sizeof(response_data)); @@ -771,25 +901,43 @@ } TEST(DnsResponseWriteTest, WrittenResponseCanBeParsed) { + std::string dotted_name("www.example.com"); net::DnsResourceRecord answer; - answer.name = "www.example.com"; + answer.name = dotted_name; answer.type = dns_protocol::kTypeA; answer.klass = dns_protocol::kClassIN; answer.ttl = 120; // 120 seconds. answer.rdata = base::StringPiece("\xc0\xa8\x00\x01", 4); std::vector<DnsResourceRecord> answers(1, answer); + net::DnsResourceRecord additional_record; + additional_record.name = dotted_name; + additional_record.type = dns_protocol::kTypeNSEC; + additional_record.klass = dns_protocol::kClassIN; + additional_record.ttl = 120; // 120 seconds. + additional_record.rdata = base::StringPiece("\xc0\x0c\x00\x01\x04", 5); + std::vector<DnsResourceRecord> additional_records(1, additional_record); DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/, - answers, base::nullopt); + answers, additional_records, base::nullopt); ASSERT_NE(nullptr, response.io_buffer()); EXPECT_TRUE(response.IsValid()); + EXPECT_EQ(1u, response.answer_count()); + EXPECT_EQ(1u, response.additional_answer_count()); auto parser = response.Parser(); net::DnsResourceRecord parsed_record; EXPECT_TRUE(parser.ReadRecord(&parsed_record)); + // Answer with an A record. EXPECT_EQ(answer.name, parsed_record.name); EXPECT_EQ(answer.type, parsed_record.type); EXPECT_EQ(answer.klass, parsed_record.klass); EXPECT_EQ(answer.ttl, parsed_record.ttl); EXPECT_EQ(answer.rdata, parsed_record.rdata); + // Additional NSEC record. + EXPECT_TRUE(parser.ReadRecord(&parsed_record)); + EXPECT_EQ(additional_record.name, parsed_record.name); + EXPECT_EQ(additional_record.type, parsed_record.type); + EXPECT_EQ(additional_record.klass, parsed_record.klass); + EXPECT_EQ(additional_record.ttl, parsed_record.ttl); + EXPECT_EQ(additional_record.rdata, parsed_record.rdata); } } // namespace
diff --git a/net/socket/udp_socket_unittest.cc b/net/socket/udp_socket_unittest.cc index e5530f1..9a20ccb 100644 --- a/net/socket/udp_socket_unittest.cc +++ b/net/socket/udp_socket_unittest.cc
@@ -54,6 +54,18 @@ namespace { +// Creates an address from ip address and port and writes it to |*address|. +bool CreateUDPAddress(const std::string& ip_str, + uint16_t port, + IPEndPoint* address) { + IPAddress ip_address; + if (!ip_address.AssignFromIPLiteral(ip_str)) + return false; + + *address = IPEndPoint(ip_address, port); + return true; +} + class UDPSocketTest : public PlatformTest, public WithScopedTaskEnvironment { public: UDPSocketTest() : buffer_(base::MakeRefCounted<IOBufferWithSize>(kMaxRead)) {} @@ -114,14 +126,15 @@ WriteSocket(socket, msg); } - // Creates an address from ip address and port and writes it to |*address|. - void CreateUDPAddress(const std::string& ip_str, - uint16_t port, - IPEndPoint* address) { - IPAddress ip_address; - if (!ip_address.AssignFromIPLiteral(ip_str)) - return; - *address = IPEndPoint(ip_address, port); + // And again for a bare socket + int SendToSocket(UDPSocket* socket, + std::string msg, + const IPEndPoint& address) { + scoped_refptr<StringIOBuffer> io_buffer = new StringIOBuffer(msg); + TestCompletionCallback callback; + int rv = socket->SendTo(io_buffer.get(), io_buffer->size(), address, + callback.callback()); + return callback.GetResult(rv); } // Run unit test for a connection test. @@ -310,9 +323,9 @@ std::string first_message("first message"), second_message("second message"); IPEndPoint broadcast_address; - CreateUDPAddress("127.255.255.255", kPort, &broadcast_address); + ASSERT_TRUE(CreateUDPAddress("127.255.255.255", kPort, &broadcast_address)); IPEndPoint listen_address; - CreateUDPAddress("0.0.0.0", kPort, &listen_address); + ASSERT_TRUE(CreateUDPAddress("0.0.0.0", kPort, &listen_address)); TestNetLog server1_log, server2_log; std::unique_ptr<UDPServerSocket> server1( @@ -581,7 +594,7 @@ TEST_F(UDPSocketTest, ServerSetDoNotFragment) { for (std::string ip : {"127.0.0.1", "::1"}) { IPEndPoint bind_address; - CreateUDPAddress(ip, 0, &bind_address); + ASSERT_TRUE(CreateUDPAddress(ip, 0, &bind_address)); UDPServerSocket server(nullptr, NetLogSource()); int rv = server.Listen(bind_address); // May fail on IPv6 is IPv6 is not configure @@ -630,7 +643,7 @@ const char kGroup[] = "237.132.100.17"; IPEndPoint bind_address; - CreateUDPAddress("0.0.0.0", kPort, &bind_address); + ASSERT_TRUE(CreateUDPAddress("0.0.0.0", kPort, &bind_address)); IPAddress group_ip; EXPECT_TRUE(group_ip.AssignFromIPLiteral(kGroup)); @@ -662,7 +675,7 @@ TEST_F(UDPSocketTest, MulticastOptions) { const uint16_t kPort = 9999; IPEndPoint bind_address; - CreateUDPAddress("0.0.0.0", kPort, &bind_address); + ASSERT_TRUE(CreateUDPAddress("0.0.0.0", kPort, &bind_address)); UDPSocket socket(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); // Before binding. @@ -690,7 +703,7 @@ IPEndPoint bind_address; UDPSocket client(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); // We need a real IP, but we won't actually send anything to it. - CreateUDPAddress("8.8.8.8", 9999, &bind_address); + ASSERT_TRUE(CreateUDPAddress("8.8.8.8", 9999, &bind_address)); int rv = client.Open(bind_address.GetFamily()); EXPECT_THAT(rv, IsOk()); @@ -768,120 +781,256 @@ namespace { const HANDLE kFakeHandle = (HANDLE)19; -const QOS_FLOWID kFakeFlowId = (QOS_FLOWID)27; +const QOS_FLOWID kFakeFlowId1 = (QOS_FLOWID)27; +const QOS_FLOWID kFakeFlowId2 = (QOS_FLOWID)38; -BOOL WINAPI FakeQOSCreateHandleFAIL(PQOS_VERSION version, PHANDLE handle) { - EXPECT_EQ(0, version->MinorVersion); - EXPECT_EQ(1, version->MajorVersion); - SetLastError(ERROR_OPEN_FAILED); - return false; +class TestUDPSocketWin : public UDPSocketWin { + public: + TestUDPSocketWin(QwaveAPI& qos, + DatagramSocket::BindType bind_type, + net::NetLog* net_log, + const net::NetLogSource& source) + : UDPSocketWin(bind_type, net_log, source), qos_(qos) {} + + // Overriding GetQwaveAPI causes the test class to use the injected mock + // QwaveAPI instance instead of the singleton. Ensure close is called in the + // child destructor before our mock CloseHandle is uninstalled. + ~TestUDPSocketWin() override { UDPSocketWin::Close(); } + + QwaveAPI& GetQwaveAPI() override { return qos_; } + + private: + QwaveAPI& qos_; + + DISALLOW_COPY_AND_ASSIGN(TestUDPSocketWin); +}; + +class MockQwaveAPI : public QwaveAPI { + public: + bool qwave_supported() const override { return true; } + MOCK_METHOD2(CreateHandle, BOOL(PQOS_VERSION version, PHANDLE handle)); + MOCK_METHOD1(CloseHandle, BOOL(HANDLE handle)); + + MOCK_METHOD6(AddSocketToFlow, + BOOL(HANDLE handle, + SOCKET socket, + PSOCKADDR addr, + QOS_TRAFFIC_TYPE traffic_type, + DWORD flags, + PQOS_FLOWID flow_id)); + + MOCK_METHOD4( + RemoveSocketFromFlow, + BOOL(HANDLE handle, SOCKET socket, QOS_FLOWID flow_id, DWORD reserved)); + MOCK_METHOD7(SetFlow, + BOOL(HANDLE handle, + QOS_FLOWID flow_id, + QOS_SET_FLOW op, + ULONG size, + PVOID data, + DWORD reserved, + LPOVERLAPPED overlapped)); +}; + +std::unique_ptr<UDPSocket> OpenedDscpTestClient(QwaveAPI& qos, + IPEndPoint bind_address) { + auto client = std::make_unique<TestUDPSocketWin>( + qos, DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); + int rv = client->Open(bind_address.GetFamily()); + EXPECT_THAT(rv, IsOk()); + + return client; } -BOOL WINAPI FakeQOSCreateHandle(PQOS_VERSION version, PHANDLE handle) { - EXPECT_EQ(0, version->MinorVersion); - EXPECT_EQ(1, version->MajorVersion); - *handle = kFakeHandle; - return true; +std::unique_ptr<UDPSocket> ConnectedDscpTestClient(QwaveAPI& qos) { + IPEndPoint bind_address; + // We need a real IP, but we won't actually send anything to it. + EXPECT_TRUE(CreateUDPAddress("8.8.8.8", 9999, &bind_address)); + auto client = OpenedDscpTestClient(qos, bind_address); + EXPECT_THAT(client->Connect(bind_address), IsOk()); + return client; } -BOOL WINAPI FakeQOSCloseHandle(HANDLE handle) { - EXPECT_EQ(kFakeHandle, handle); - return true; -} - -QOS_TRAFFIC_TYPE g_expected_traffic_type; - -BOOL WINAPI FakeQOSAddSocketToFlow(HANDLE handle, - SOCKET socket, - PSOCKADDR addr, - QOS_TRAFFIC_TYPE traffic_type, - DWORD flags, - PQOS_FLOWID flow_id) { - EXPECT_EQ(kFakeHandle, handle); - EXPECT_EQ(NULL, addr); - EXPECT_EQ(static_cast<DWORD>(QOS_NON_ADAPTIVE_FLOW), flags); - EXPECT_EQ(0u, *flow_id); - *flow_id = kFakeFlowId; - return true; -} - -BOOL WINAPI FakeQOSRemoveSocketFromFlow(HANDLE handle, - SOCKET socket, - QOS_FLOWID flowid, - DWORD reserved) { - EXPECT_EQ(kFakeHandle, handle); - EXPECT_EQ(0u, socket); - EXPECT_EQ(kFakeFlowId, flowid); - EXPECT_EQ(0u, reserved); - return true; -} - -DWORD g_expected_dscp; - -BOOL WINAPI FakeQOSSetFlow(HANDLE handle, - QOS_FLOWID flow_id, - QOS_SET_FLOW op, - ULONG size, - PVOID data, - DWORD reserved, - LPOVERLAPPED overlapped) { - EXPECT_EQ(kFakeHandle, handle); - EXPECT_EQ(QOSSetOutgoingDSCPValue, op); - EXPECT_EQ(sizeof(DWORD), size); - EXPECT_EQ(g_expected_dscp, *reinterpret_cast<DWORD*>(data)); - EXPECT_EQ(kFakeFlowId, flow_id); - EXPECT_EQ(0u, reserved); - EXPECT_EQ(NULL, overlapped); - return true; +std::unique_ptr<UDPSocket> UnconnectedDscpTestClient(QwaveAPI& qos) { + IPEndPoint bind_address; + EXPECT_TRUE(CreateUDPAddress("0.0.0.0", 9999, &bind_address)); + auto client = OpenedDscpTestClient(qos, bind_address); + EXPECT_THAT(client->Bind(bind_address), IsOk()); + return client; } } // namespace -// Mock out the Qwave functions and make sure they are -// called correctly. Must be in net namespace for friendship -// reasons. -TEST_F(UDPSocketTest, SetDSCPFake) { - // Setup the server to listen. - IPEndPoint bind_address; - // We need a real IP, but we won't actually send anything to it. - CreateUDPAddress("8.8.8.8", 9999, &bind_address); - UDPSocket client(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource()); - int rv = client.SetDiffServCodePoint(DSCP_AF41); - EXPECT_THAT(rv, IsError(ERR_SOCKET_NOT_CONNECTED)); +using ::testing::_; +using ::testing::Return; +using ::testing::SetArgPointee; - rv = client.Open(bind_address.GetFamily()); - EXPECT_THAT(rv, IsOk()); +TEST_F(UDPSocketTest, SetDSCPNoopIfPassedNoChange) { + MockQwaveAPI qos; + std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos); + EXPECT_THAT(client->SetDiffServCodePoint(DSCP_NO_CHANGE), IsOk()); +} - rv = client.Connect(bind_address); - EXPECT_THAT(rv, IsOk()); +TEST_F(UDPSocketTest, SetDSCPFailsIfQOSHandleCanNotBeCreated) { + MockQwaveAPI qos; + EXPECT_CALL(qos, CreateHandle(_, _)).WillOnce(Return(false)); + std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos); - QwaveAPI& qos(QwaveAPI::Get()); - qos.create_handle_func_ = FakeQOSCreateHandleFAIL; - qos.close_handle_func_ = FakeQOSCloseHandle; - qos.add_socket_to_flow_func_ = FakeQOSAddSocketToFlow; - qos.remove_socket_from_flow_func_ = FakeQOSRemoveSocketFromFlow; - qos.set_flow_func_ = FakeQOSSetFlow; - qos.qwave_supported_ = true; + EXPECT_EQ(ERR_NOT_IMPLEMENTED, client->SetDiffServCodePoint(DSCP_AF41)); +} - EXPECT_THAT(client.SetDiffServCodePoint(DSCP_NO_CHANGE), IsOk()); - EXPECT_EQ(ERROR_NOT_SUPPORTED, client.SetDiffServCodePoint(DSCP_AF41)); - qos.create_handle_func_ = FakeQOSCreateHandle; - g_expected_dscp = DSCP_AF41; - g_expected_traffic_type = QOSTrafficTypeAudioVideo; - EXPECT_THAT(client.SetDiffServCodePoint(DSCP_AF41), IsOk()); - g_expected_dscp = DSCP_DEFAULT; - g_expected_traffic_type = QOSTrafficTypeBestEffort; - EXPECT_THAT(client.SetDiffServCodePoint(DSCP_DEFAULT), IsOk()); - g_expected_dscp = DSCP_CS2; - g_expected_traffic_type = QOSTrafficTypeExcellentEffort; - EXPECT_THAT(client.SetDiffServCodePoint(DSCP_CS2), IsOk()); - g_expected_dscp = DSCP_CS3; - g_expected_traffic_type = QOSTrafficTypeExcellentEffort; - EXPECT_THAT(client.SetDiffServCodePoint(DSCP_NO_CHANGE), IsOk()); - g_expected_dscp = DSCP_DEFAULT; - g_expected_traffic_type = QOSTrafficTypeBestEffort; - EXPECT_THAT(client.SetDiffServCodePoint(DSCP_DEFAULT), IsOk()); - client.Close(); +MATCHER_P(DscpPointee, dscp, "") { + return *(DWORD*)arg == (DWORD)dscp; +} + +TEST_F(UDPSocketTest, SetDSCPCallsQwaveFunctions) { + MockQwaveAPI qos; + std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos); + + EXPECT_CALL(qos, CreateHandle(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle), Return(true))); + // AddSocketToFlow also sets flow_id, but we don't use that here + EXPECT_CALL(qos, AddSocketToFlow(_, _, _, QOSTrafficTypeAudioVideo, _, _)) + .WillOnce(Return(true)); + EXPECT_CALL(qos, SetFlow(_, _, QOSSetOutgoingDSCPValue, _, + DscpPointee(DSCP_AF41), _, _)); + EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF41), IsOk()); + EXPECT_CALL(qos, CloseHandle(kFakeHandle)); +} + +TEST_F(UDPSocketTest, SecondSetDSCPCallsQwaveFunctions) { + MockQwaveAPI qos; + std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos); + + EXPECT_CALL(qos, CreateHandle(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle), Return(true))); + + EXPECT_CALL(qos, AddSocketToFlow(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true))); + EXPECT_CALL(qos, SetFlow(_, _, _, _, _, _, _)); + EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF41), IsOk()); + + // New dscp value should reset the flow. + EXPECT_CALL(qos, RemoveSocketFromFlow(_, _, _, _)); + EXPECT_CALL(qos, AddSocketToFlow(_, _, _, QOSTrafficTypeBestEffort, _, _)) + .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId2), Return(true))); + EXPECT_CALL(qos, SetFlow(_, _, QOSSetOutgoingDSCPValue, _, + DscpPointee(DSCP_DEFAULT), _, _)); + EXPECT_THAT(client->SetDiffServCodePoint(DSCP_DEFAULT), IsOk()); + + // Called from DscpManager destructor. + EXPECT_CALL(qos, RemoveSocketFromFlow(_, _, _, _)); + EXPECT_CALL(qos, CloseHandle(kFakeHandle)); +} + +// TODO(zstein): Mocking out DscpManager might be simpler here +// (just verify that DscpManager::Set and DscpManager::PrepareForSend are +// called). +TEST_F(UDPSocketTest, SendToCallsQwaveApis) { + MockQwaveAPI qos; + std::unique_ptr<UDPSocket> client = UnconnectedDscpTestClient(qos); + + EXPECT_CALL(qos, CreateHandle(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle), Return(true))); + EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF41), IsOk()); + + EXPECT_CALL(qos, AddSocketToFlow(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true))); + EXPECT_CALL(qos, SetFlow(_, _, _, _, _, _, _)); + + std::string simple_message("hello world"); + IPEndPoint server_address(IPAddress::IPv4Localhost(), 9438); + int rv = SendToSocket(client.get(), simple_message, server_address); + EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); + + // TODO(zstein): Move to second test case (Qwave APIs called once per address) + rv = SendToSocket(client.get(), simple_message, server_address); + EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); + + // TODO(zstein): Move to third test case (Qwave APIs called for each + // destination address). + EXPECT_CALL(qos, AddSocketToFlow(_, _, _, _, _, _)).WillOnce(Return(true)); + IPEndPoint server_address2(IPAddress::IPv4Localhost(), 9439); + + rv = SendToSocket(client.get(), simple_message, server_address2); + EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv)); + + // Called from DscpManager destructor. + EXPECT_CALL(qos, RemoveSocketFromFlow(_, _, _, _)); + EXPECT_CALL(qos, CloseHandle(kFakeHandle)); +} + +class DscpManagerTest : public testing::Test { + protected: + DscpManagerTest() : dscp_manager_(qos_, INVALID_SOCKET, (HANDLE)0) { + CreateUDPAddress("1.2.3.4", 9001, &address1_); + CreateUDPAddress("1234:5678:90ab:cdef:1234:5678:90ab:cdef", 9002, + &address2_); + } + + MockQwaveAPI qos_; + DscpManager dscp_manager_; + + IPEndPoint address1_; + IPEndPoint address2_; +}; + +TEST_F(DscpManagerTest, PrepareForSendIsNoopIfNoSet) { + dscp_manager_.PrepareForSend(address1_); +} + +TEST_F(DscpManagerTest, PrepareForSendCallsQwaveApisAfterSet) { + dscp_manager_.Set(DSCP_CS2); + + // AddSocketToFlow should be called for each address. + EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true))) + .WillOnce(Return(true)); + // SetFlow should only be called when the flow is first created. + EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)); + dscp_manager_.PrepareForSend(address1_); + EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)).Times(0); + dscp_manager_.PrepareForSend(address2_); + + // Called from DscpManager destructor. + EXPECT_CALL(qos_, RemoveSocketFromFlow(_, _, _, _)); +} + +TEST_F(DscpManagerTest, PrepareForSendCallsQwaveApisOncePerAddress) { + dscp_manager_.Set(DSCP_CS2); + + EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true))); + EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)); + dscp_manager_.PrepareForSend(address1_); + EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)).Times(0); + dscp_manager_.PrepareForSend(address1_); + + // Called from DscpManager destructor. + EXPECT_CALL(qos_, RemoveSocketFromFlow(_, _, _, _)); +} + +TEST_F(DscpManagerTest, SetDestroysExistingFlowAndResetsPrepareState) { + dscp_manager_.Set(DSCP_CS2); + EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true))); + EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)); + dscp_manager_.PrepareForSend(address1_); + + // Calling Set should destroy the existing flow. + // TODO(zstein): Verify that RemoveSocketFromFlow with no address + // destroys the flow for all destinations. + EXPECT_CALL(qos_, RemoveSocketFromFlow(_, NULL, kFakeFlowId1, _)); + dscp_manager_.Set(DSCP_CS5); + + EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId2), Return(true))); + EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)); + dscp_manager_.PrepareForSend(address1_); + + // Called from DscpManager destructor. + EXPECT_CALL(qos_, RemoveSocketFromFlow(_, _, kFakeFlowId2, _)); } #endif
diff --git a/net/socket/udp_socket_win.cc b/net/socket/udp_socket_win.cc index 945d9e8b..d7c01f7 100644 --- a/net/socket/udp_socket_win.cc +++ b/net/socket/udp_socket_win.cc
@@ -56,7 +56,7 @@ void WatchForWrite(); // The UDPSocketWin is going away. - void Detach() { socket_ = NULL; } + void Detach() { socket_ = nullptr; } // The separate OVERLAPPED variables for asynchronous operation. OVERLAPPED read_overlapped_; @@ -260,7 +260,6 @@ recv_from_address_(nullptr), net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::UDP_SOCKET)), qos_handle_(nullptr), - qos_flow_id_(0), event_pending_(this) { EnsureWinsockInit(); net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE, @@ -296,12 +295,15 @@ if (socket_ == INVALID_SOCKET) return; - if (qos_handle_) - QwaveAPI::Get().CloseHandle(qos_handle_); + if (qos_handle_) { + GetQwaveAPI().CloseHandle(qos_handle_); + dscp_manager_ = nullptr; + qos_handle_ = NULL; + } // Zero out any pending read/write callback state. read_callback_.Reset(); - recv_from_address_ = NULL; + recv_from_address_ = nullptr; write_callback_.Reset(); base::TimeTicks start_time = base::TimeTicks::Now(); @@ -325,7 +327,7 @@ if (core_) { core_->Detach(); - core_ = NULL; + core_ = nullptr; } } @@ -378,7 +380,7 @@ int UDPSocketWin::Read(IOBuffer* buf, int buf_len, CompletionOnceCallback callback) { - return RecvFrom(buf, buf_len, NULL, std::move(callback)); + return RecvFrom(buf, buf_len, nullptr, std::move(callback)); } int UDPSocketWin::RecvFrom(IOBuffer* buf, @@ -415,6 +417,13 @@ int buf_len, const IPEndPoint& address, CompletionOnceCallback callback) { + if (dscp_manager_) { + // Alert DscpManager in case this is a new remote address. Failure to + // apply Dscp code is never fatal. + int rv = dscp_manager_->PrepareForSend(address); + if (rv != OK) + net_log_.AddEventWithNetErrorCode(NetLogEventType::UDP_SEND_ERROR, rv); + } return SendToOrWrite(buf, buf_len, &address, std::move(callback)); } @@ -481,6 +490,10 @@ return MapSystemError(WSAGetLastError()); remote_address_.reset(new IPEndPoint(address)); + + if (dscp_manager_) + dscp_manager_->PrepareForSend(*remote_address_.get()); + return rv; } @@ -611,7 +624,7 @@ int result = ok ? num_bytes : MapSystemError(WSAGetLastError()); // Convert address. IPEndPoint address; - IPEndPoint* address_to_log = NULL; + IPEndPoint* address_to_log = nullptr; if (result >= 0) { if (address.FromSockAddr(core_->recv_addr_storage_.addr, core_->recv_addr_storage_.addr_len)) { @@ -623,8 +636,8 @@ } } LogRead(result, core_->read_iobuffer_->data(), address_to_log); - core_->read_iobuffer_ = NULL; - recv_from_address_ = NULL; + core_->read_iobuffer_ = nullptr; + recv_from_address_ = nullptr; DoReadCallback(result); } @@ -637,7 +650,7 @@ LogWrite(result, core_->write_iobuffer_->data(), send_to_address_.get()); send_to_address_.reset(); - core_->write_iobuffer_ = NULL; + core_->write_iobuffer_ = nullptr; DoWriteCallback(result); } @@ -691,9 +704,9 @@ recv_from_address_); if (rv == ERR_IO_PENDING) return; - read_iobuffer_ = NULL; + read_iobuffer_ = nullptr; read_iobuffer_len_ = 0; - recv_from_address_ = NULL; + recv_from_address_ = nullptr; DoReadCallback(rv); } @@ -702,7 +715,7 @@ send_to_address_.get()); if (rv == ERR_IO_PENDING) return; - write_iobuffer_ = NULL; + write_iobuffer_ = nullptr; write_iobuffer_len_ = 0; send_to_address_.reset(); DoWriteCallback(rv); @@ -767,13 +780,13 @@ CHECK_NE(INVALID_SOCKET, socket_); AssertEventNotSignaled(core_->read_overlapped_.hEvent); int rv = WSARecvFrom(socket_, &read_buffer, 1, &num, &flags, storage.addr, - &storage.addr_len, &core_->read_overlapped_, NULL); + &storage.addr_len, &core_->read_overlapped_, nullptr); if (rv == 0) { if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) { int result = num; // Convert address. IPEndPoint address_storage; - IPEndPoint* address_to_log = NULL; + IPEndPoint* address_to_log = nullptr; if (result >= 0) { if (address_storage.FromSockAddr(core_->recv_addr_storage_.addr, core_->recv_addr_storage_.addr_len)) { @@ -791,7 +804,7 @@ int os_error = WSAGetLastError(); if (os_error != WSA_IO_PENDING) { int result = MapSystemError(os_error); - LogRead(result, NULL, NULL); + LogRead(result, nullptr, nullptr); return result; } } @@ -808,12 +821,12 @@ struct sockaddr* addr = storage.addr; // Convert address. if (!address) { - addr = NULL; + addr = nullptr; storage.addr_len = 0; } else { if (!address->ToSockAddr(addr, &storage.addr_len)) { int result = ERR_ADDRESS_INVALID; - LogWrite(result, NULL, NULL); + LogWrite(result, nullptr, nullptr); return result; } } @@ -825,8 +838,8 @@ DWORD flags = 0; DWORD num; AssertEventNotSignaled(core_->write_overlapped_.hEvent); - int rv = WSASendTo(socket_, &write_buffer, 1, &num, flags, - addr, storage.addr_len, &core_->write_overlapped_, NULL); + int rv = WSASendTo(socket_, &write_buffer, 1, &num, flags, addr, + storage.addr_len, &core_->write_overlapped_, nullptr); if (rv == 0) { if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) { int result = num; @@ -837,7 +850,7 @@ int os_error = WSAGetLastError(); if (os_error != WSA_IO_PENDING) { int result = MapSystemError(os_error); - LogWrite(result, NULL, NULL); + LogWrite(result, nullptr, nullptr); return result; } } @@ -866,11 +879,11 @@ return ERR_IO_PENDING; } rv = MapSystemError(os_error); - LogRead(rv, NULL, NULL); + LogRead(rv, nullptr, nullptr); return rv; } IPEndPoint address_storage; - IPEndPoint* address_to_log = NULL; + IPEndPoint* address_to_log = nullptr; if (rv >= 0) { if (address_storage.FromSockAddr(storage.addr, storage.addr_len)) { if (address) @@ -894,11 +907,11 @@ if (address) { if (!address->ToSockAddr(addr, &storage.addr_len)) { int result = ERR_ADDRESS_INVALID; - LogWrite(result, NULL, NULL); + LogWrite(result, nullptr, nullptr); return result; } } else { - addr = NULL; + addr = nullptr; storage.addr_len = 0; } @@ -912,7 +925,7 @@ return ERR_IO_PENDING; } rv = MapSystemError(os_error); - LogWrite(rv, NULL, NULL); + LogWrite(rv, nullptr, nullptr); return rv; } LogWrite(rv, buf->data(), address); @@ -1002,6 +1015,10 @@ return DoBind(IPEndPoint(address, 0)); } +QwaveAPI& UDPSocketWin::GetQwaveAPI() { + return QwaveAPI::Get(); +} + int UDPSocketWin::JoinGroup(const IPAddress& group_address) const { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (!is_connected()) @@ -1111,28 +1128,7 @@ return OK; } -int UDPSocketWin::SetDiffServCodePoint(DiffServCodePoint dscp) { - if (dscp == DSCP_NO_CHANGE) { - return OK; - } - - if (!is_connected()) - return ERR_SOCKET_NOT_CONNECTED; - - QwaveAPI& qos(QwaveAPI::Get()); - - if (!qos.qwave_supported()) - return ERROR_NOT_SUPPORTED; - - if (qos_handle_ == NULL) { - QOS_VERSION version; - version.MajorVersion = 1; - version.MinorVersion = 0; - qos.CreateHandle(&version, &qos_handle_); - if (qos_handle_ == NULL) - return ERROR_NOT_SUPPORTED; - } - +QOS_TRAFFIC_TYPE DscpToTrafficType(DiffServCodePoint dscp) { QOS_TRAFFIC_TYPE traffic_type = QOSTrafficTypeBestEffort; switch (dscp) { case DSCP_CS0: @@ -1172,34 +1168,36 @@ NOTREACHED(); break; } - if (qos_flow_id_ != 0) { - qos.RemoveSocketFromFlow(qos_handle_, NULL, qos_flow_id_, 0); - qos_flow_id_ = 0; + return traffic_type; +} + +int UDPSocketWin::SetDiffServCodePoint(DiffServCodePoint dscp) { + if (dscp == DSCP_NO_CHANGE) + return OK; + + if (!is_connected()) + return ERR_SOCKET_NOT_CONNECTED; + + QwaveAPI& qos(GetQwaveAPI()); + + if (!qos.qwave_supported()) + return ERR_NOT_IMPLEMENTED; + + if (!qos_handle_) { + QOS_VERSION version; + version.MajorVersion = 1; + version.MinorVersion = 0; + qos.CreateHandle(&version, &qos_handle_); + if (!qos_handle_) + return ERR_NOT_IMPLEMENTED; } - if (!qos.AddSocketToFlow(qos_handle_, - socket_, - NULL, - traffic_type, - QOS_NON_ADAPTIVE_FLOW, - &qos_flow_id_)) { - DWORD err = GetLastError(); - if (err == ERROR_DEVICE_REINITIALIZATION_NEEDED) { - qos.CloseHandle(qos_handle_); - qos_flow_id_ = 0; - qos_handle_ = 0; - } - return MapSystemError(err); - } - // This requires admin rights, and may fail, if so we ignore it - // as AddSocketToFlow should still do *approximately* the right thing. - DWORD buf = dscp; - qos.SetFlow(qos_handle_, - qos_flow_id_, - QOSSetOutgoingDSCPValue, - sizeof(buf), - &buf, - 0, - NULL); + + if (!dscp_manager_) + dscp_manager_ = std::make_unique<DscpManager>(qos, socket_, qos_handle_); + + dscp_manager_->Set(dscp); + if (remote_address_) + return dscp_manager_->PrepareForSend(*remote_address_.get()); return OK; } @@ -1250,5 +1248,70 @@ NOTIMPLEMENTED(); return result; } +DscpManager::DscpManager(QwaveAPI& qos, SOCKET socket, HANDLE qos_handle) + : qos_(qos), socket_(socket), qos_handle_(qos_handle) {} + +DscpManager::~DscpManager() { + if (flow_id_ != 0) + qos_.RemoveSocketFromFlow(qos_handle_, NULL, flow_id_, 0); +} + +void DscpManager::Set(DiffServCodePoint dscp) { + if (dscp == DSCP_NO_CHANGE || dscp == dscp_value_) + return; + + dscp_value_ = dscp; + // TODO(zstein): We could reuse the flow when the value changes + // by calling QOSSetFlow with the new traffic type and dscp value. + if (flow_id_ != 0) { + qos_.RemoveSocketFromFlow(qos_handle_, NULL, flow_id_, 0); + configured_.clear(); + flow_id_ = 0; + } +} + +int DscpManager::PrepareForSend(const IPEndPoint& remote_address) { + if (dscp_value_ == DSCP_NO_CHANGE) { + // No DSCP value has been set. + return OK; + } + + if (configured_.find(remote_address) != configured_.end()) + return OK; + + SockaddrStorage storage; + if (!remote_address.ToSockAddr(storage.addr, &storage.addr_len)) + return ERR_ADDRESS_INVALID; + + // We won't try again if we get an error. + configured_.emplace(remote_address); + + // We don't need to call SetFlow if we already have a qos flow. + bool new_flow = flow_id_ == 0; + + const QOS_TRAFFIC_TYPE traffic_type = DscpToTrafficType(dscp_value_); + + if (!qos_.AddSocketToFlow(qos_handle_, socket_, storage.addr, traffic_type, + QOS_NON_ADAPTIVE_FLOW, &flow_id_)) { + DWORD err = GetLastError(); + if (err == ERROR_DEVICE_REINITIALIZATION_NEEDED) { + qos_.CloseHandle(qos_handle_); + flow_id_ = 0; + qos_handle_ = 0; + dscp_value_ = DSCP_NO_CHANGE; + } + return MapSystemError(err); + } + + if (new_flow) { + DWORD buf = dscp_value_; + // This requires admin rights, and may fail, if so we ignore it + // as AddSocketToFlow should still do *approximately* the right thing. + qos_.SetFlow(qos_handle_, flow_id_, QOSSetOutgoingDSCPValue, sizeof(buf), + &buf, 0, nullptr); + } + + return OK; +} } // namespace net
diff --git a/net/socket/udp_socket_win.h b/net/socket/udp_socket_win.h index 81cd245f..8240fc86 100644 --- a/net/socket/udp_socket_win.h +++ b/net/socket/udp_socket_win.h
@@ -37,6 +37,110 @@ struct NetLogSource; class SocketTag; +// QWAVE (Quality Windows Audio/Video Experience) is the latest windows +// library for setting packet priorities (and other things). Unfortunately, +// Microsoft has decided that setting the DSCP bits with setsockopt() no +// longer works, so we have to use this API instead. +// This class is meant to be used as a singleton. It exposes a few dynamically +// loaded functions and a bool called "qwave_supported". +class NET_EXPORT QwaveAPI { + typedef BOOL(WINAPI* CreateHandleFn)(PQOS_VERSION, PHANDLE); + typedef BOOL(WINAPI* CloseHandleFn)(HANDLE); + typedef BOOL(WINAPI* AddSocketToFlowFn)(HANDLE, + SOCKET, + PSOCKADDR, + QOS_TRAFFIC_TYPE, + DWORD, + PQOS_FLOWID); + typedef BOOL(WINAPI* RemoveSocketFromFlowFn)(HANDLE, + SOCKET, + QOS_FLOWID, + DWORD); + typedef BOOL(WINAPI* SetFlowFn)(HANDLE, + QOS_FLOWID, + QOS_SET_FLOW, + ULONG, + PVOID, + DWORD, + LPOVERLAPPED); + + public: + QwaveAPI(); + virtual ~QwaveAPI() = default; + + static QwaveAPI& Get(); + + virtual bool qwave_supported() const; + virtual BOOL CreateHandle(PQOS_VERSION version, PHANDLE handle); + virtual BOOL CloseHandle(HANDLE handle); + virtual BOOL AddSocketToFlow(HANDLE handle, + SOCKET socket, + PSOCKADDR addr, + QOS_TRAFFIC_TYPE traffic_type, + DWORD flags, + PQOS_FLOWID flow_id); + virtual BOOL RemoveSocketFromFlow(HANDLE handle, + SOCKET socket, + QOS_FLOWID flow_id, + DWORD reserved); + virtual BOOL SetFlow(HANDLE handle, + QOS_FLOWID flow_id, + QOS_SET_FLOW op, + ULONG size, + PVOID data, + DWORD reserved, + LPOVERLAPPED overlapped); + + private: + FRIEND_TEST_ALL_PREFIXES(UDPSocketTest, SetDSCPFake); + + bool qwave_supported_; + CreateHandleFn create_handle_func_; + CloseHandleFn close_handle_func_; + AddSocketToFlowFn add_socket_to_flow_func_; + RemoveSocketFromFlowFn remove_socket_from_flow_func_; + SetFlowFn set_flow_func_; + + DISALLOW_COPY_AND_ASSIGN(QwaveAPI); +}; + +//----------------------------------------------------------------------------- + +// Helper for maintaining the state that (unlike a blanket socket option), DSCP +// values are set per-remote endpoint instead of just per-socket on Windows. +// The implementation creates a single QWAVE 'flow' for the socket, and adds +// all encountered remote addresses to that flow. Flows are the minimum +// manageable unit within the QWAVE API. See +// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/api/qos2/ +// for Microsoft's documentation. +class NET_EXPORT DscpManager { + public: + DscpManager(QwaveAPI& qos, SOCKET socket, HANDLE qos_handle); + ~DscpManager(); + + // Remembers the latest |dscp| so PrepareToSend can add remote addresses to + // the qos flow. Destroys the old flow if it exists and |dscp| changes. + void Set(DiffServCodePoint dscp); + + // Constructs a qos flow for the latest set DSCP value if we don't already + // have one. Adds |remote_address| to the qos flow if it hasn't been added + // already. Does nothing if no DSCP value has been Set. + int PrepareForSend(const IPEndPoint& remote_address); + + private: + QwaveAPI& qos_; + SOCKET socket_; + HANDLE qos_handle_; + + DiffServCodePoint dscp_value_ = DSCP_NO_CHANGE; + // The remote addresses currently in the flow. + std::set<IPEndPoint> configured_; + // 0 means no flow has been constructed. + QOS_FLOWID flow_id_ = 0; +}; + +//----------------------------------------------------------------------------- + class NET_EXPORT UDPSocketWin : public base::win::ObjectWatcher::Delegate { public: UDPSocketWin(DatagramSocket::BindType bind_type, @@ -285,6 +389,11 @@ // Binds to a random port on |address|. int RandomBind(const IPAddress& address); + // This is provided to allow QwaveAPI mocking in tests. |UDPSocketWin| method + // implementations should call |GetQwaveAPI()| instead of |QwaveAPI::Get()| + // directly. + virtual QwaveAPI& GetQwaveAPI(); + SOCKET socket_; int addr_family_; bool is_connected_; @@ -346,7 +455,9 @@ // QWAVE data. Used to set DSCP bits on outgoing packets. HANDLE qos_handle_; - QOS_FLOWID qos_flow_id_; + + // Maintains remote addresses for QWAVE qos management. + std::unique_ptr<DscpManager> dscp_manager_; THREAD_CHECKER(thread_checker_); @@ -359,60 +470,6 @@ //----------------------------------------------------------------------------- -// QWAVE (Quality Windows Audio/Video Experience) is the latest windows -// library for setting packet priorities (and other things). Unfortunately, -// Microsoft has decided that setting the DSCP bits with setsockopt() no -// longer works, so we have to use this API instead. -// This class is meant to be used as a singleton. It exposes a few dynamically -// loaded functions and a bool called "qwave_supported". -class NET_EXPORT QwaveAPI { - typedef BOOL (WINAPI *CreateHandleFn)(PQOS_VERSION, PHANDLE); - typedef BOOL (WINAPI *CloseHandleFn)(HANDLE); - typedef BOOL (WINAPI *AddSocketToFlowFn)( - HANDLE, SOCKET, PSOCKADDR, QOS_TRAFFIC_TYPE, DWORD, PQOS_FLOWID); - typedef BOOL (WINAPI *RemoveSocketFromFlowFn)( - HANDLE, SOCKET, QOS_FLOWID, DWORD); - typedef BOOL (WINAPI *SetFlowFn)( - HANDLE, QOS_FLOWID, QOS_SET_FLOW, ULONG, PVOID, DWORD, LPOVERLAPPED); - - public: - QwaveAPI(); - - static QwaveAPI& Get(); - - bool qwave_supported() const; - BOOL CreateHandle(PQOS_VERSION version, PHANDLE handle); - BOOL CloseHandle(HANDLE handle); - BOOL AddSocketToFlow(HANDLE handle, - SOCKET socket, - PSOCKADDR addr, - QOS_TRAFFIC_TYPE traffic_type, - DWORD flags, - PQOS_FLOWID flow_id); - BOOL RemoveSocketFromFlow(HANDLE handle, - SOCKET socket, - QOS_FLOWID flow_id, - DWORD reserved); - BOOL SetFlow(HANDLE handle, - QOS_FLOWID flow_id, - QOS_SET_FLOW op, - ULONG size, - PVOID data, - DWORD reserved, - LPOVERLAPPED overlapped); - - private: - FRIEND_TEST_ALL_PREFIXES(UDPSocketTest, SetDSCPFake); - - bool qwave_supported_; - CreateHandleFn create_handle_func_; - CloseHandleFn close_handle_func_; - AddSocketToFlowFn add_socket_to_flow_func_; - RemoveSocketFromFlowFn remove_socket_from_flow_func_; - SetFlowFn set_flow_func_; - - DISALLOW_COPY_AND_ASSIGN(QwaveAPI); -}; } // namespace net
diff --git a/ppapi/api/OWNERS b/ppapi/api/OWNERS deleted file mode 100644 index df227dd98..0000000 --- a/ppapi/api/OWNERS +++ /dev/null
@@ -1,7 +0,0 @@ -# Changing the PPAPI requires sending an explicit design doc discussing -# the features missing from the open web platform, and the transition plan. -set noparent - -file://ENG_REVIEW_OWNERS - -# COMPONENT: Internals>Plugins>Pepper
diff --git a/ppapi/shared_impl/ppb_tcp_socket_shared.cc b/ppapi/shared_impl/ppb_tcp_socket_shared.cc index 94fb45e..d4588cd 100644 --- a/ppapi/shared_impl/ppb_tcp_socket_shared.cc +++ b/ppapi/shared_impl/ppb_tcp_socket_shared.cc
@@ -36,8 +36,7 @@ state_ = success ? SSL_CONNECTED : CLOSED; break; case LISTEN: - if (success) - state_ = LISTENING; + state_ = success ? LISTENING : CLOSED; break; case CLOSE: state_ = CLOSED;
diff --git a/ppapi/tests/test_tcp_server_socket_private.cc b/ppapi/tests/test_tcp_server_socket_private.cc index 64b5402..7d4e7dd 100644 --- a/ppapi/tests/test_tcp_server_socket_private.cc +++ b/ppapi/tests/test_tcp_server_socket_private.cc
@@ -56,6 +56,9 @@ void TestTCPServerSocketPrivate::RunTests(const std::string& filter) { RUN_CALLBACK_TEST(TestTCPServerSocketPrivate, Listen, filter); RUN_CALLBACK_TEST(TestTCPServerSocketPrivate, Backlog, filter); + + RUN_CALLBACK_TEST(TestTCPServerSocketPrivate, ListenFails, filter); + RUN_CALLBACK_TEST(TestTCPServerSocketPrivate, AcceptFails, filter); } std::string TestTCPServerSocketPrivate::GetLocalAddress( @@ -122,6 +125,30 @@ } while (!error_message.empty()); } +std::string TestTCPServerSocketPrivate::SyncListenFails( + pp::TCPServerSocketPrivate* socket) { + uint8_t localhost_ip[4] = {127, 0, 0, 1}; + PP_NetAddress_Private ipv4; + ASSERT_TRUE( + NetAddressPrivate::CreateFromIPv4Address(localhost_ip, 80, &ipv4)); + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + callback.WaitForResult( + socket->Listen(&ipv4, 2 /* backlog */, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_FAILED, callback.result()); + PASS(); +} + +std::string TestTCPServerSocketPrivate::SyncAcceptFails( + pp::TCPServerSocketPrivate* socket) { + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + PP_Resource resource; + callback.WaitForResult(socket->Accept(&resource, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_FAILED, callback.result()); + PASS(); +} + std::string TestTCPServerSocketPrivate::SyncListen( TCPServerSocketPrivate* socket, PP_NetAddress_Private* address, @@ -262,3 +289,39 @@ server_socket.StopListening(); PASS(); } + +std::string TestTCPServerSocketPrivate::TestListenFails() { + TCPServerSocketPrivate socket(instance_); + ASSERT_SUBTEST_SUCCESS(SyncListenFails(&socket)); + + // After a listen failure, accept should fail, too. + ASSERT_SUBTEST_SUCCESS(SyncAcceptFails(&socket)); + + // Listening again fails, just because of the test fixture simulating another + // failure. + ASSERT_SUBTEST_SUCCESS(SyncListenFails(&socket)); + + PASS(); +} + +std::string TestTCPServerSocketPrivate::TestAcceptFails() { + TCPServerSocketPrivate socket(instance_); + uint8_t localhost_ip[4] = {127, 0, 0, 1}; + PP_NetAddress_Private ipv4; + ASSERT_TRUE( + NetAddressPrivate::CreateFromIPv4Address(localhost_ip, 80, &ipv4)); + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + callback.WaitForResult( + socket.Listen(&ipv4, 2 /* backlog */, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + // Accept calls should fail. + ASSERT_SUBTEST_SUCCESS(SyncAcceptFails(&socket)); + ASSERT_SUBTEST_SUCCESS(SyncAcceptFails(&socket)); + + // Listening again fails, since the socket is already listening. + ASSERT_SUBTEST_SUCCESS(SyncListenFails(&socket)); + + PASS(); +}
diff --git a/ppapi/tests/test_tcp_server_socket_private.h b/ppapi/tests/test_tcp_server_socket_private.h index e54c788..b371389 100644 --- a/ppapi/tests/test_tcp_server_socket_private.h +++ b/ppapi/tests/test_tcp_server_socket_private.h
@@ -46,9 +46,18 @@ PP_NetAddress_Private* address, int32_t backlog); + // Checks that a listen/accept attempt on |socket| fails. + std::string SyncListenFails(pp::TCPServerSocketPrivate* socket); + std::string SyncAcceptFails(pp::TCPServerSocketPrivate* socket); + std::string TestListen(); std::string TestBacklog(); + // The higher level test fixture must configure the corresponding events to + // fail with PP_ERROR_FAILED. + std::string TestListenFails(); + std::string TestAcceptFails(); + std::string host_; uint16_t port_; };
diff --git a/ppapi/tests/test_tcp_socket.cc b/ppapi/tests/test_tcp_socket.cc index 620bd4e..cd227677 100644 --- a/ppapi/tests/test_tcp_socket.cc +++ b/ppapi/tests/test_tcp_socket.cc
@@ -63,6 +63,20 @@ RUN_CALLBACK_TEST(TestTCPSocket, Backlog, filter); RUN_CALLBACK_TEST(TestTCPSocket, Interface_1_0, filter); RUN_CALLBACK_TEST(TestTCPSocket, UnexpectedCalls, filter); + + RUN_CALLBACK_TEST(TestTCPSocket, ConnectFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, WriteFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, ReadFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, SetSendBufferSizeFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, SetReceiveBufferSizeFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, SetNoDelayFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, BindFailsConnectSucceeds, filter); + RUN_CALLBACK_TEST(TestTCPSocket, BindFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, ListenFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, AcceptFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, AcceptedSocketWriteFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, AcceptedSocketReadFails, filter); + RUN_CALLBACK_TEST(TestTCPSocket, BindConnectFails, filter); } std::string TestTCPSocket::TestConnect() { @@ -444,14 +458,17 @@ pp::TCPSocket client_socket(instance_); TestCompletionCallback connect_callback(instance_->pp_instance(), callback_type()); - client_socket.Connect(server_socket.GetLocalAddress(), - connect_callback.GetCallback()); + int connect_result = client_socket.Connect(server_socket.GetLocalAddress(), + connect_callback.GetCallback()); TestCompletionCallbackWithOutput<pp::TCPSocket> accept_callback( instance_->pp_instance(), callback_type()); accept_callback.WaitForResult( server_socket.Accept(accept_callback.GetCallback())); CHECK_CALLBACK_BEHAVIOR(accept_callback); ASSERT_EQ(PP_OK, accept_callback.result()); + connect_callback.WaitForResult(connect_result); + CHECK_CALLBACK_BEHAVIOR(connect_callback); + ASSERT_EQ(PP_OK, connect_callback.result()); pp::TCPSocket accepted_socket(accept_callback.output()); ASSERT_SUBTEST_SUCCESS(RunCommandsExpendingFailures( &server_socket, kBind | kListen | kConnect | kReadWrite)); @@ -464,6 +481,295 @@ PASS(); } +std::string TestTCPSocket::TestConnectFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + + cb.WaitForResult(socket.Connect(test_server_addr_, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + + // All subsequent calls on the socket should fail. + ASSERT_SUBTEST_SUCCESS(RunCommandsExpendingFailures(&socket, kAllCommands)); + + PASS(); +} + +std::string TestTCPSocket::TestWriteFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + cb.WaitForResult(socket.Connect(test_server_addr_, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + // Write to the socket until there's an error. Some writes may succeed, since + // Mojo writes complete before the socket tries to send data. As with the read + // case, wait for two errors. + char write_data[32 * 1024] = {0}; + int failures = 0; + while (true) { + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + cb.WaitForResult(socket.Write(write_data, + static_cast<int32_t>(sizeof(write_data)), + cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + if (cb.result() > 0) { + ASSERT_EQ(0, failures); + continue; + } + + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + ++failures; + + if (failures == 2) + break; + } + + PASS(); +} + +std::string TestTCPSocket::TestReadFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + cb.WaitForResult(socket.Connect(test_server_addr_, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + std::string read_data; + int read_error; + // Read should fail with no data received. + ASSERT_SUBTEST_SUCCESS( + ReadFromSocketUntilError(&socket, &read_data, &read_error)); + ASSERT_EQ(PP_ERROR_FAILED, read_error); + ASSERT_EQ(0, read_data.size()); + + // Reading again after the socket has been closed should also fail. + ASSERT_SUBTEST_SUCCESS( + ReadFromSocketUntilError(&socket, &read_data, &read_error)); + ASSERT_EQ(PP_ERROR_FAILED, read_error); + ASSERT_EQ(0, read_data.size()); + + PASS(); +} + +std::string TestTCPSocket::TestSetSendBufferSizeFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + cb.WaitForResult(socket.Connect(test_server_addr_, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + cb.WaitForResult(socket.SetOption(PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE, 256, + cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + PASS(); +} + +std::string TestTCPSocket::TestSetReceiveBufferSizeFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + cb.WaitForResult(socket.Connect(test_server_addr_, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + cb.WaitForResult(socket.SetOption(PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE, 256, + cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + PASS(); +} + +std::string TestTCPSocket::TestSetNoDelayFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + cb.WaitForResult(socket.Connect(test_server_addr_, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + cb.WaitForResult( + socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY, true, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + PASS(); +} + +std::string TestTCPSocket::TestBindFailsConnectSucceeds() { + pp::TCPSocket socket(instance_); + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + // The address doesn't matter here, other than that it should be valid. + callback.WaitForResult( + socket.Bind(test_server_addr_, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_FAILED, callback.result()); + + callback.WaitForResult( + socket.Connect(test_server_addr_, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + PASS(); +} + +std::string TestTCPSocket::TestBindFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + // The address doesn't matter here, other than that it should be valid. + callback.WaitForResult( + socket.Bind(test_server_addr_, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_FAILED, callback.result()); + + PASS(); +} + +std::string TestTCPSocket::TestListenFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + // The address doesn't matter here, other than that it should be valid. + callback.WaitForResult( + socket.Bind(test_server_addr_, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + callback.WaitForResult( + socket.Listen(2 /* backlog */, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_FAILED, callback.result()); + + // All subsequent calls on the socket should fail. + ASSERT_SUBTEST_SUCCESS(RunCommandsExpendingFailures(&socket, kAllCommands)); + + PASS(); +} + +std::string TestTCPSocket::TestAcceptFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + // The address doesn't matter here, other than that it should be valid. + callback.WaitForResult( + socket.Bind(test_server_addr_, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + callback.WaitForResult( + socket.Listen(2 /* backlog */, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + TestCompletionCallbackWithOutput<pp::TCPSocket> accept_callback( + instance_->pp_instance(), callback_type()); + accept_callback.WaitForResult(socket.Accept(accept_callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(accept_callback); + ASSERT_EQ(PP_ERROR_FAILED, accept_callback.result()); + + PASS(); +} + +std::string TestTCPSocket::TestAcceptedSocketWriteFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + // The address doesn't matter here, other than that it should be valid. + callback.WaitForResult( + socket.Bind(test_server_addr_, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + callback.WaitForResult( + socket.Listen(2 /* backlog */, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + TestCompletionCallbackWithOutput<pp::TCPSocket> accept_callback( + instance_->pp_instance(), callback_type()); + accept_callback.WaitForResult(socket.Accept(accept_callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(accept_callback); + ASSERT_EQ(PP_OK, accept_callback.result()); + + pp::TCPSocket accepted_socket(accept_callback.output()); + + // Write to the socket until there's an error. Some writes may succeed, since + // Mojo writes complete before the socket tries to send data. As with the read + // case, wait for two errors. + char write_data[32 * 1024] = {0}; + int failures = 0; + while (true) { + callback.WaitForResult(accepted_socket.Write( + write_data, static_cast<int32_t>(sizeof(write_data)), + callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + if (callback.result() > 0) { + ASSERT_EQ(0, failures); + continue; + } + + ASSERT_EQ(PP_ERROR_FAILED, callback.result()); + ++failures; + + if (failures == 2) + break; + } + + PASS(); +} + +std::string TestTCPSocket::TestAcceptedSocketReadFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + // The address doesn't matter here, other than that it should be valid. + callback.WaitForResult( + socket.Bind(test_server_addr_, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + callback.WaitForResult( + socket.Listen(2 /* backlog */, callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + TestCompletionCallbackWithOutput<pp::TCPSocket> accept_callback( + instance_->pp_instance(), callback_type()); + accept_callback.WaitForResult(socket.Accept(accept_callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(accept_callback); + ASSERT_EQ(PP_OK, accept_callback.result()); + + pp::TCPSocket accepted_socket(accept_callback.output()); + + std::string read_data; + int read_error; + // Read should fail with no data received. + ASSERT_SUBTEST_SUCCESS( + ReadFromSocketUntilError(&accepted_socket, &read_data, &read_error)); + ASSERT_EQ(PP_ERROR_FAILED, read_error); + ASSERT_EQ(0, read_data.size()); + + // Reading again after the socket has been closed should also fail. + ASSERT_SUBTEST_SUCCESS( + ReadFromSocketUntilError(&accepted_socket, &read_data, &read_error)); + ASSERT_EQ(PP_ERROR_FAILED, read_error); + ASSERT_EQ(0, read_data.size()); + + PASS(); +} + +std::string TestTCPSocket::TestBindConnectFails() { + pp::TCPSocket socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + + cb.WaitForResult(socket.Bind(test_server_addr_, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + cb.WaitForResult(socket.Connect(test_server_addr_, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + + // All subsequent calls on the socket should fail. + ASSERT_SUBTEST_SUCCESS(RunCommandsExpendingFailures(&socket, kAllCommands)); + + PASS(); +} + std::string TestTCPSocket::ReadFirstLineFromSocket(pp::TCPSocket* socket, std::string* s) { char buffer[1000]; @@ -627,7 +933,8 @@ if (commands & kBind) { TestCompletionCallback cb(instance_->pp_instance(), callback_type()); pp::NetAddress any_port_address; - ASSERT_SUBTEST_SUCCESS(GetAddressToBind(&any_port_address)); + ASSERT_TRUE(ReplacePort(instance_->pp_instance(), test_server_addr_, 0, + &any_port_address)); cb.WaitForResult(socket->Bind(any_port_address, cb.GetCallback())); CHECK_CALLBACK_BEHAVIOR(cb); ASSERT_EQ(PP_ERROR_FAILED, cb.result());
diff --git a/ppapi/tests/test_tcp_socket.h b/ppapi/tests/test_tcp_socket.h index 80d3742..0a0e206 100644 --- a/ppapi/tests/test_tcp_socket.h +++ b/ppapi/tests/test_tcp_socket.h
@@ -35,6 +35,26 @@ std::string TestInterface_1_0(); std::string TestUnexpectedCalls(); + // The higher level test fixture is responsible for making the appropriate + // call in these tests fail with PP_ERROR_FAILED, and all prior events + // succeed. + std::string TestConnectFails(); + std::string TestWriteFails(); + std::string TestReadFails(); + std::string TestSetSendBufferSizeFails(); + std::string TestSetReceiveBufferSizeFails(); + std::string TestSetNoDelayFails(); + // When a bind call fails, normally the socket is reuseable. + std::string TestBindFailsConnectSucceeds(); + // This is needed in addition to the above test in the case where a bind + // failure is simulated in a way that also closes the NetworkContext pipe. + std::string TestBindFails(); + std::string TestListenFails(); + std::string TestAcceptFails(); + std::string TestAcceptedSocketWriteFails(); + std::string TestAcceptedSocketReadFails(); + std::string TestBindConnectFails(); + std::string ReadFirstLineFromSocket(pp::TCPSocket* socket, std::string* s); std::string ReadFirstLineFromSocket_1_0(PP_Resource socket, std::string* s); @@ -65,6 +85,7 @@ kAccept = 0x4, kConnect = 0x8, kReadWrite = 0x10, + kAllCommands = -1, }; // Runs |commands|, consisting of one or more Command values on |socket|, // expecting all of them to fail with PP_ERROR_FAILED. Useful for testing
diff --git a/ppapi/tests/test_tcp_socket_private.cc b/ppapi/tests/test_tcp_socket_private.cc index ae7b472..5037d0b 100644 --- a/ppapi/tests/test_tcp_socket_private.cc +++ b/ppapi/tests/test_tcp_socket_private.cc
@@ -56,6 +56,10 @@ RUN_CALLBACK_TEST(TestTCPSocketPrivate, ConnectAddress, filter); RUN_CALLBACK_TEST(TestTCPSocketPrivate, SetOption, filter); RUN_CALLBACK_TEST(TestTCPSocketPrivate, LargeRead, filter); + + RUN_CALLBACK_TEST(TestTCPSocketPrivate, SSLHandshakeFails, filter); + RUN_CALLBACK_TEST(TestTCPSocketPrivate, SSLWriteFails, filter); + RUN_CALLBACK_TEST(TestTCPSocketPrivate, SSLReadFails, filter); } std::string TestTCPSocketPrivate::TestBasic() { @@ -214,6 +218,81 @@ PASS(); } +std::string TestTCPSocketPrivate::TestSSLHandshakeFails() { + pp::TCPSocketPrivate socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + + cb.WaitForResult(socket.Connect("foo.test", 443, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + cb.WaitForResult(socket.SSLHandshake("foo.test", 443, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + + // Writes and reads should both fail after an SSL handshake fails. + + char byte = 'a'; + cb.WaitForResult(socket.Write(&byte, 1, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + + cb.WaitForResult(socket.Read(&byte, 1, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + + PASS(); +} + +std::string TestTCPSocketPrivate::TestSSLWriteFails() { + pp::TCPSocketPrivate socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + + cb.WaitForResult(socket.Connect("foo.test", 443, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + cb.WaitForResult(socket.SSLHandshake("foo.test", 443, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + // Write to the socket until there's an error. Some writes may succeed, since + // Mojo writes complete before the socket tries to send data. + char write_data[32 * 1024] = {0}; + while (true) { + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + cb.WaitForResult(socket.Write(write_data, + static_cast<int32_t>(sizeof(write_data)), + cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + if (cb.result() > 0) + continue; + + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + PASS(); + } +} + +std::string TestTCPSocketPrivate::TestSSLReadFails() { + pp::TCPSocketPrivate socket(instance_); + TestCompletionCallback cb(instance_->pp_instance(), callback_type()); + + cb.WaitForResult(socket.Connect("foo.test", 443, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + cb.WaitForResult(socket.SSLHandshake("foo.test", 443, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_OK, cb.result()); + + char byte; + cb.WaitForResult(socket.Read(&byte, 1, cb.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(cb); + ASSERT_EQ(PP_ERROR_FAILED, cb.result()); + + PASS(); +} + int32_t TestTCPSocketPrivate::ReadFirstLineFromSocket( pp::TCPSocketPrivate* socket, std::string* s) {
diff --git a/ppapi/tests/test_tcp_socket_private.h b/ppapi/tests/test_tcp_socket_private.h index 4396cfc..13fa1cf 100644 --- a/ppapi/tests/test_tcp_socket_private.h +++ b/ppapi/tests/test_tcp_socket_private.h
@@ -30,6 +30,13 @@ std::string TestSetOption(); std::string TestLargeRead(); + // The higher level test fixture is responsible for making the appropriate + // call in these tests fail with PP_ERROR_FAILED, and all prior events + // succeed. + std::string TestSSLHandshakeFails(); + std::string TestSSLWriteFails(); + std::string TestSSLReadFails(); + int32_t ReadFirstLineFromSocket(pp::TCPSocketPrivate* socket, std::string* s); int32_t WriteStringToSocket(pp::TCPSocketPrivate* socket, const std::string& s);
diff --git a/remoting/host/sas_injector_win.cc b/remoting/host/sas_injector_win.cc index 70fa7e9d..d4b7182b 100644 --- a/remoting/host/sas_injector_win.cc +++ b/remoting/host/sas_injector_win.cc
@@ -7,9 +7,11 @@ #include <windows.h> #include <sas.h> +#include <memory> +#include <utility> + #include "base/logging.h" #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/win/registry.h" namespace remoting { @@ -38,14 +40,12 @@ base::win::RegKey system_policy_; // True if the policy needs to be restored. - bool restore_policy_; + bool restore_policy_ = false; DISALLOW_COPY_AND_ASSIGN(ScopedSoftwareSasPolicy); }; -ScopedSoftwareSasPolicy::ScopedSoftwareSasPolicy() - : restore_policy_(false) { -} +ScopedSoftwareSasPolicy::ScopedSoftwareSasPolicy() = default; ScopedSoftwareSasPolicy::~ScopedSoftwareSasPolicy() { // Restore the default policy by deleting the value that we have set. @@ -103,10 +103,9 @@ DISALLOW_COPY_AND_ASSIGN(SasInjectorWin); }; -SasInjectorWin::SasInjectorWin() {} +SasInjectorWin::SasInjectorWin() = default; -SasInjectorWin::~SasInjectorWin() { -} +SasInjectorWin::~SasInjectorWin() = default; bool SasInjectorWin::InjectSas() { // Enable software SAS generation by services and send SAS. SAS can still fail @@ -121,7 +120,7 @@ } std::unique_ptr<SasInjector> SasInjector::Create() { - return base::WrapUnique(new SasInjectorWin()); + return std::make_unique<SasInjectorWin>(); } } // namespace remoting
diff --git a/remoting/host/win/session_input_injector.cc b/remoting/host/win/session_input_injector.cc index 7b61dc5..a52725e 100644 --- a/remoting/host/win/session_input_injector.cc +++ b/remoting/host/win/session_input_injector.cc
@@ -94,9 +94,6 @@ // Used to lock the current session on non-home SKUs of Windows. base::Closure lock_workstation_; - // Used to inject Secure Attention Sequence on XP. - std::unique_ptr<SasInjector> sas_injector_; - // Keys currently pressed by the client, used to detect key sequences. std::set<ui::DomCode> pressed_keys_;
diff --git a/services/device/bluetooth/bluetooth_system.cc b/services/device/bluetooth/bluetooth_system.cc index 4153f35..d9583e2 100644 --- a/services/device/bluetooth/bluetooth_system.cc +++ b/services/device/bluetooth/bluetooth_system.cc
@@ -24,27 +24,48 @@ BluetoothSystem::BluetoothSystem(mojom::BluetoothSystemClientPtr client) { client_ptr_ = std::move(client); GetBluetoothAdapterClient()->AddObserver(this); - UpdateActiveAdapter(); + + std::vector<dbus::ObjectPath> object_paths = + GetBluetoothAdapterClient()->GetAdapters(); + if (!object_paths.empty()) + active_adapter_ = object_paths[0]; } BluetoothSystem::~BluetoothSystem() = default; void BluetoothSystem::AdapterAdded(const dbus::ObjectPath& object_path) { - UpdateActiveAdapter(); + if (!active_adapter_) + active_adapter_ = object_path; } void BluetoothSystem::AdapterRemoved(const dbus::ObjectPath& object_path) { - UpdateActiveAdapter(); + DCHECK(active_adapter_); + + if (active_adapter_.value() != object_path) + return; + + active_adapter_ = base::nullopt; + + std::vector<dbus::ObjectPath> object_paths = + GetBluetoothAdapterClient()->GetAdapters(); + for (const auto& new_object_path : object_paths) { + // The removed adapter is still included in GetAdapters(). + if (new_object_path == object_path) + continue; + + active_adapter_ = new_object_path; + break; + } } void BluetoothSystem::GetState(GetStateCallback callback) { - if (active_adapter_.value().empty()) { + if (!active_adapter_) { std::move(callback).Run(State::kUnavailable); return; } auto* properties = - GetBluetoothAdapterClient()->GetProperties(active_adapter_); + GetBluetoothAdapterClient()->GetProperties(active_adapter_.value()); std::move(callback).Run(properties->powered.value() ? State::kPoweredOn : State::kPoweredOff); } @@ -55,18 +76,4 @@ return bluez::BluezDBusManager::Get()->GetAlternateBluetoothAdapterClient(); } -void BluetoothSystem::UpdateActiveAdapter() { - std::vector<dbus::ObjectPath> object_paths = - GetBluetoothAdapterClient()->GetAdapters(); - if (object_paths.empty()) { - active_adapter_ = dbus::ObjectPath(""); - return; - } - - if (base::ContainsValue(object_paths, active_adapter_)) - return; - - active_adapter_ = object_paths[0]; -} - } // namespace device
diff --git a/services/device/bluetooth/bluetooth_system.h b/services/device/bluetooth/bluetooth_system.h index 21d033d..b44d76f 100644 --- a/services/device/bluetooth/bluetooth_system.h +++ b/services/device/bluetooth/bluetooth_system.h
@@ -6,6 +6,7 @@ #define SERVICES_DEVICE_BLUETOOTH_BLUETOOTH_SYSTEM_H_ #include "base/macros.h" +#include "base/optional.h" #include "dbus/object_path.h" #include "device/bluetooth/dbus/bluetooth_adapter_client.h" #include "services/device/public/mojom/bluetooth_system.mojom.h" @@ -35,11 +36,11 @@ private: bluez::BluetoothAdapterClient* GetBluetoothAdapterClient(); - void UpdateActiveAdapter(); - mojom::BluetoothSystemClientPtr client_ptr_; - dbus::ObjectPath active_adapter_; + // The ObjectPath of the adapter being used. Updated as BT adapters are + // added and removed. nullopt if there is no adapter. + base::Optional<dbus::ObjectPath> active_adapter_; DISALLOW_COPY_AND_ASSIGN(BluetoothSystem); };
diff --git a/services/device/bluetooth/bluetooth_system_unittest.cc b/services/device/bluetooth/bluetooth_system_unittest.cc index db393e37..e4b54d11 100644 --- a/services/device/bluetooth/bluetooth_system_unittest.cc +++ b/services/device/bluetooth/bluetooth_system_unittest.cc
@@ -85,11 +85,14 @@ // Simulates the adapter at |object_path_str| being removed. void SimulateAdapterRemoved(const std::string& object_path_str) { dbus::ObjectPath object_path(object_path_str); - size_t removed = adapter_object_paths_to_properties_.erase(object_path); - DCHECK_EQ(1u, removed); + // When BlueZ calls into AdapterRemoved, the adapter is still exposed + // through GetAdapters() and its properties are still accessible. for (auto& observer : observers_) observer.AdapterRemoved(object_path); + + size_t removed = adapter_object_paths_to_properties_.erase(object_path); + DCHECK_EQ(1u, removed); } // Simulates adapter at |object_path_str| changing its powered state to
diff --git a/services/media_session/audio_focus_manager.cc b/services/media_session/audio_focus_manager.cc index b0e72d2..f40dec4 100644 --- a/services/media_session/audio_focus_manager.cc +++ b/services/media_session/audio_focus_manager.cc
@@ -7,9 +7,9 @@ #include <iterator> #include <utility> -#include "base/atomic_sequence_num.h" #include "base/containers/adapters.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/unguessable_token.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "services/media_session/audio_focus_manager_metrics_helper.h" #include "services/media_session/public/cpp/switches.h" @@ -17,17 +17,6 @@ namespace media_session { -namespace { - -// Generate a unique audio focus request ID for the audio focus request. The IDs -// are only handed out by the audio focus manager. -int GenerateAudioFocusRequestId() { - static base::AtomicSequenceNumber request_id; - return request_id.GetNext(); -} - -} // namespace - class AudioFocusManager::StackRow : public mojom::AudioFocusRequestClient { public: StackRow(AudioFocusManager* owner, @@ -172,7 +161,7 @@ RequestAudioFocusInternal( std::make_unique<StackRow>( this, std::move(request), std::move(media_session), - std::move(session_info), type, GenerateAudioFocusRequestId(), + std::move(session_info), type, base::UnguessableToken::Create(), GetBindingSourceName()), type, std::move(callback)); } @@ -193,7 +182,7 @@ } void AudioFocusManager::GetDebugInfoForRequest( - uint64_t request_id, + const RequestId& request_id, GetDebugInfoForRequestCallback callback) { for (auto& row : audio_focus_stack_) { if (row->id() != request_id)
diff --git a/services/media_session/audio_focus_manager.h b/services/media_session/audio_focus_manager.h index 18b8526..cd9f845 100644 --- a/services/media_session/audio_focus_manager.h +++ b/services/media_session/audio_focus_manager.h
@@ -17,12 +17,17 @@ #include "mojo/public/cpp/bindings/interface_ptr_set.h" #include "services/media_session/public/mojom/audio_focus.mojom.h" +namespace base { +class UnguessableToken; +} // namespace base + namespace media_session { class AudioFocusManager : public mojom::AudioFocusManager, public mojom::AudioFocusManagerDebug { public: - using RequestId = uint64_t; + // TODO(beccahughes): Remove this. + using RequestId = base::UnguessableToken; // Returns Chromium's internal AudioFocusManager. static AudioFocusManager* GetInstance(); @@ -38,7 +43,7 @@ void SetSourceName(const std::string& name) override; // mojom::AudioFocusManagerDebug. - void GetDebugInfoForRequest(uint64_t request_id, + void GetDebugInfoForRequest(const RequestId& request_id, GetDebugInfoForRequestCallback callback) override; // Bind to a mojom::AudioFocusManagerRequest.
diff --git a/services/media_session/audio_focus_manager_unittest.cc b/services/media_session/audio_focus_manager_unittest.cc index 6068ac5..3f441ab0 100644 --- a/services/media_session/audio_focus_manager_unittest.cc +++ b/services/media_session/audio_focus_manager_unittest.cc
@@ -30,8 +30,6 @@ namespace { -const AudioFocusManager::RequestId kNoFocusedSession = -1; - const char kExampleDebugInfoName[] = "name"; const char kExampleDebugInfoOwner[] = "owner"; const char kExampleDebugInfoState[] = "state"; @@ -181,9 +179,9 @@ for (auto iter = audio_focus_requests.rbegin(); iter != audio_focus_requests.rend(); ++iter) { if ((*iter)->audio_focus_type == mojom::AudioFocusType::kGain) - return (*iter)->request_id; + return (*iter)->request_id.value(); } - return kNoFocusedSession; + return base::UnguessableToken::Null(); } int GetTransientCount() { @@ -357,15 +355,15 @@ AudioFocusManager::RequestId GetRequestIdForSession( MockMediaSession* session) { DCHECK(session->HasAudioFocusRequest()); - AudioFocusManager::RequestId id = kNoFocusedSession; + AudioFocusManager::RequestId id = base::UnguessableToken::Null(); - session->audio_focus_request()->GetRequestId( - base::BindOnce([](AudioFocusManager::RequestId* id, - uint64_t received_id) { *id = received_id; }, - &id)); + session->audio_focus_request()->GetRequestId(base::BindOnce( + [](AudioFocusManager::RequestId* id, + const base::UnguessableToken& received_id) { *id = received_id; }, + &id)); session->FlushForTesting(); - EXPECT_NE(kNoFocusedSession, id); + EXPECT_NE(base::UnguessableToken::Null(), id); return id; } @@ -413,7 +411,7 @@ MockMediaSession media_session_2; MockMediaSession media_session_3; - EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); + EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kInactive, GetState(&media_session_1)); EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kInactive, @@ -445,7 +443,7 @@ TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_Duplicate) { MockMediaSession media_session; - EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); + EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); AudioFocusManager::RequestId request_id = RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); @@ -460,7 +458,7 @@ AudioFocusManager::RequestId request_id = RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient); - EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); + EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); EXPECT_EQ(1, GetTransientCount()); RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); @@ -473,7 +471,7 @@ AudioFocusManager::RequestId request_id = RequestAudioFocus( &media_session, mojom::AudioFocusType::kGainTransientMayDuck); - EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); + EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); EXPECT_EQ(1, GetTransientMaybeDuckCount()); RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); @@ -491,7 +489,7 @@ EXPECT_EQ(0, GetTransientCount()); RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient); - EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); + EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); EXPECT_EQ(1, GetTransientCount()); EXPECT_NE(mojom::MediaSessionInfo::SessionState::kSuspended, GetState(&media_session)); @@ -508,7 +506,7 @@ RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransientMayDuck); - EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); + EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); EXPECT_EQ(1, GetTransientMaybeDuckCount()); EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, GetState(&media_session)); @@ -568,7 +566,7 @@ EXPECT_EQ(request_id, GetAudioFocusedSession()); AbandonAudioFocus(&media_session); - EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); + EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); } TEST_P(AudioFocusManagerTest, AbandonAudioFocus_MultipleCalls) { @@ -583,7 +581,7 @@ std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); AbandonAudioFocus(&media_session); - EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); + EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); EXPECT_TRUE(observer->focus_lost_session_.is_null()); } @@ -782,7 +780,7 @@ MockMediaSession media_session; RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransientMayDuck); - EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); + EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); } TEST_P(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesTransient) { @@ -912,7 +910,8 @@ } TEST_P(AudioFocusManagerTest, GetDebugInfo_BadRequestId) { - mojom::MediaSessionDebugInfoPtr debug_info = GetDebugInfo(kNoFocusedSession); + mojom::MediaSessionDebugInfoPtr debug_info = + GetDebugInfo(base::UnguessableToken::Create()); EXPECT_TRUE(debug_info->name.empty()); }
diff --git a/services/media_session/public/mojom/audio_focus.mojom b/services/media_session/public/mojom/audio_focus.mojom index 6f9454b..9ad4b27a 100644 --- a/services/media_session/public/mojom/audio_focus.mojom +++ b/services/media_session/public/mojom/audio_focus.mojom
@@ -4,9 +4,10 @@ module media_session.mojom; +import "mojo/public/mojom/base/unguessable_token.mojom"; import "services/media_session/public/mojom/media_session.mojom"; -// Next MinVersion: 2 +// Next MinVersion: 4 // These are the different types of audio focus that can be requested. [Extensible] @@ -31,8 +32,9 @@ struct AudioFocusRequestState { MediaSessionInfo session_info; AudioFocusType audio_focus_type; - uint64 request_id; + [MinVersion=2] string? source_name; + [MinVersion=3] mojo_base.mojom.UnguessableToken? request_id; }; // The observer for audio focus events. @@ -46,7 +48,8 @@ }; // Controls audio focus for an associated request. -// Next Method ID: 4 +// Next Method ID: 5 +// Deprecated method IDs: 3 interface AudioFocusRequestClient { // Requests updated audio focus for this request. If the request was granted // then the callback will resolve. @@ -59,7 +62,8 @@ MediaSessionInfoChanged@2(MediaSessionInfo session_info); // Retrieve a unique ID for this request. - GetRequestId@3() => (uint64 request_id); + [MinVersion=3] GetRequestId@4() + => (mojo_base.mojom.UnguessableToken request_id); }; // Controls audio focus across the entire system. @@ -91,6 +95,6 @@ // Provides debug information about audio focus requests. interface AudioFocusManagerDebug { // Gets debugging information for a |MediaSession| with |request_id|. - GetDebugInfoForRequest(uint64 request_id) + GetDebugInfoForRequest(mojo_base.mojom.UnguessableToken request_id) => (MediaSessionDebugInfo debug_info); };
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn index fd192f1..6bb2296 100644 --- a/services/network/BUILD.gn +++ b/services/network/BUILD.gn
@@ -67,6 +67,8 @@ "network_service.h", "network_service_network_delegate.cc", "network_service_network_delegate.h", + "network_service_proxy_delegate.cc", + "network_service_proxy_delegate.h", "network_usage_accumulator.cc", "network_usage_accumulator.h", "p2p/socket.cc", @@ -187,6 +189,7 @@ "//services/service_manager/sandbox:sandbox", "//third_party/webrtc/media:rtc_media_base", "//third_party/webrtc/rtc_base", + "//third_party/webrtc/rtc_base:timeutils", "//third_party/webrtc_overrides", "//third_party/webrtc_overrides:init_webrtc", "//url", @@ -245,6 +248,7 @@ "network_change_manager_unittest.cc", "network_context_unittest.cc", "network_quality_estimator_manager_unittest.cc", + "network_service_proxy_delegate_unittest.cc", "network_service_unittest.cc", "network_usage_accumulator_unittest.cc", "p2p/socket_tcp_server_unittest.cc",
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index 56fff6b..642fa57 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -74,6 +74,7 @@ #include "services/network/mojo_net_log.h" #include "services/network/network_service.h" #include "services/network/network_service_network_delegate.h" +#include "services/network/network_service_proxy_delegate.h" #include "services/network/p2p/socket_manager.h" #include "services/network/proxy_config_service_mojo.h" #include "services/network/proxy_lookup_request.h" @@ -1480,6 +1481,12 @@ std::make_unique<NetworkServiceNetworkDelegate>(this); builder.set_network_delegate(std::move(network_delegate)); + if (params_->custom_proxy_config_client_request) { + proxy_delegate_ = std::make_unique<NetworkServiceProxyDelegate>( + std::move(params_->custom_proxy_config_client_request)); + builder.set_shared_proxy_delegate(proxy_delegate_.get()); + } + // |network_service_| may be nullptr in tests. auto result = ApplyContextParamsToBuilder(&builder);
diff --git a/services/network/network_context.h b/services/network/network_context.h index 87ffad9f9..3bcf928 100644 --- a/services/network/network_context.h +++ b/services/network/network_context.h
@@ -61,6 +61,7 @@ class ExpectCTReporter; class HostResolver; class NetworkService; +class NetworkServiceProxyDelegate; class P2PSocketManager; class ProxyLookupRequest; class ResourceScheduler; @@ -279,6 +280,10 @@ return proxy_lookup_requests_.size(); } + NetworkServiceProxyDelegate* proxy_delegate() const { + return proxy_delegate_.get(); + } + private: class ContextNetworkDelegate; @@ -394,6 +399,8 @@ std::set<std::unique_ptr<HostResolver>, base::UniquePtrComparator> host_resolvers_; + std::unique_ptr<NetworkServiceProxyDelegate> proxy_delegate_; + // Used for Signed Exchange certificate verification. int next_cert_verify_id_ = 0; struct PendingCertVerify {
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc index 818a624..dab6b0d6 100644 --- a/services/network/network_context_unittest.cc +++ b/services/network/network_context_unittest.cc
@@ -20,6 +20,7 @@ #include "base/optional.h" #include "base/run_loop.h" #include "base/stl_util.h" +#include "base/strings/strcat.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/waitable_event.h" @@ -69,6 +70,7 @@ #include "net/ssl/channel_id_store.h" #include "net/test/cert_test_util.h" #include "net/test/embedded_test_server/controllable_http_response.h" +#include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server_connection_listener.h" #include "net/test/gtest_util.h" @@ -108,6 +110,7 @@ const GURL kURL("http://foo.com"); const GURL kOtherURL("http://other.com"); +constexpr char kMockHost[] = "mock.host"; // Sends an HttpResponse for requests for "/" that result in sending an HPKP // report. Ignores other paths to avoid catching the subsequent favicon @@ -159,6 +162,27 @@ false)}); } +std::unique_ptr<TestURLLoaderClient> FetchRequest( + const ResourceRequest& request, + NetworkContext* network_context) { + mojom::URLLoaderFactoryPtr loader_factory; + auto params = mojom::URLLoaderFactoryParams::New(); + params->process_id = mojom::kBrowserProcessId; + params->is_corb_enabled = false; + network_context->CreateURLLoaderFactory(mojo::MakeRequest(&loader_factory), + std::move(params)); + + auto client = std::make_unique<TestURLLoaderClient>(); + mojom::URLLoaderPtr loader; + loader_factory->CreateLoaderAndStart( + mojo::MakeRequest(&loader), 0 /* routing_id */, 0 /* request_id */, + 0 /* options */, request, client->CreateInterfacePtr(), + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)); + + client->RunUntilComplete(); + return client; +} + // ProxyLookupClient that drives proxy lookups and can wait for the responses to // be received. class TestProxyLookupClient : public mojom::ProxyLookupClient { @@ -3826,6 +3850,320 @@ } } +// Custom proxy does not apply to localhost, so resolve kMockHost to localhost, +// and use that instead. +class NetworkContextMockHostTest : public NetworkContextTest { + public: + NetworkContextMockHostTest() { + auto host_resolver = std::make_unique<net::MockHostResolver>(); + host_resolver->rules()->AddRule(kMockHost, "127.0.0.1"); + network_service_->SetHostResolver(std::move(host_resolver)); + } + + protected: + GURL GetURLWithMockHost(const net::EmbeddedTestServer& server, + const std::string& relative_url) { + GURL server_base_url = server.base_url(); + GURL base_url = + GURL(base::StrCat({server_base_url.scheme(), "://", kMockHost, ":", + server_base_url.port()})); + EXPECT_TRUE(base_url.is_valid()) << base_url.possibly_invalid_spec(); + return base_url.Resolve(relative_url); + } +}; + +TEST_F(NetworkContextMockHostTest, CustomProxyAddsHeaders) { + net::EmbeddedTestServer test_server; + ASSERT_TRUE(test_server.Start()); + + net::EmbeddedTestServer proxy_test_server; + net::test_server::RegisterDefaultHandlers(&proxy_test_server); + ASSERT_TRUE(proxy_test_server.Start()); + + mojom::CustomProxyConfigClientPtr proxy_config_client; + mojom::NetworkContextParamsPtr context_params = CreateContextParams(); + context_params->custom_proxy_config_client_request = + mojo::MakeRequest(&proxy_config_client); + std::unique_ptr<NetworkContext> network_context = + CreateContextWithParams(std::move(context_params)); + + auto config = mojom::CustomProxyConfig::New(); + std::string base_url = proxy_test_server.base_url().spec(); + // Remove slash from URL. + base_url.pop_back(); + config->rules.ParseFromString("http=" + base_url); + config->pre_cache_headers.SetHeader("pre_foo", "pre_foo_value"); + config->post_cache_headers.SetHeader("post_foo", "post_foo_value"); + proxy_config_client->OnCustomProxyConfigUpdated(std::move(config)); + scoped_task_environment_.RunUntilIdle(); + + ResourceRequest request; + request.custom_proxy_pre_cache_headers.SetHeader("pre_bar", "pre_bar_value"); + request.custom_proxy_post_cache_headers.SetHeader("post_bar", + "post_bar_value"); + request.url = GetURLWithMockHost( + test_server, "/echoheader?pre_foo&post_foo&pre_bar&post_bar"); + std::unique_ptr<TestURLLoaderClient> client = + FetchRequest(request, network_context.get()); + std::string response; + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &response)); + + EXPECT_EQ(response, base::JoinString({"post_bar_value", "post_foo_value", + "pre_bar_value", "pre_foo_value"}, + "\n")); + EXPECT_EQ(client->response_head().proxy_server, + net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP)); +} + +TEST_F(NetworkContextMockHostTest, + CustomProxyRequestHeadersOverrideConfigHeaders) { + net::EmbeddedTestServer test_server; + ASSERT_TRUE(test_server.Start()); + + net::EmbeddedTestServer proxy_test_server; + net::test_server::RegisterDefaultHandlers(&proxy_test_server); + ASSERT_TRUE(proxy_test_server.Start()); + + mojom::CustomProxyConfigClientPtr proxy_config_client; + mojom::NetworkContextParamsPtr context_params = CreateContextParams(); + context_params->custom_proxy_config_client_request = + mojo::MakeRequest(&proxy_config_client); + std::unique_ptr<NetworkContext> network_context = + CreateContextWithParams(std::move(context_params)); + + auto config = mojom::CustomProxyConfig::New(); + std::string base_url = proxy_test_server.base_url().spec(); + // Remove slash from URL. + base_url.pop_back(); + config->rules.ParseFromString("http=" + base_url); + config->pre_cache_headers.SetHeader("foo", "bad"); + config->post_cache_headers.SetHeader("bar", "bad"); + proxy_config_client->OnCustomProxyConfigUpdated(std::move(config)); + scoped_task_environment_.RunUntilIdle(); + + ResourceRequest request; + request.custom_proxy_pre_cache_headers.SetHeader("foo", "foo_value"); + request.custom_proxy_post_cache_headers.SetHeader("bar", "bar_value"); + request.url = GetURLWithMockHost(test_server, "/echoheader?foo&bar"); + std::unique_ptr<TestURLLoaderClient> client = + FetchRequest(request, network_context.get()); + std::string response; + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &response)); + + EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n")); + EXPECT_EQ(client->response_head().proxy_server, + net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP)); +} + +TEST_F(NetworkContextMockHostTest, CustomProxyConfigHeadersAddedBeforeCache) { + net::EmbeddedTestServer test_server; + ASSERT_TRUE(test_server.Start()); + + net::EmbeddedTestServer proxy_test_server; + net::test_server::RegisterDefaultHandlers(&proxy_test_server); + ASSERT_TRUE(proxy_test_server.Start()); + + mojom::CustomProxyConfigClientPtr proxy_config_client; + mojom::NetworkContextParamsPtr context_params = CreateContextParams(); + context_params->custom_proxy_config_client_request = + mojo::MakeRequest(&proxy_config_client); + std::unique_ptr<NetworkContext> network_context = + CreateContextWithParams(std::move(context_params)); + + auto config = mojom::CustomProxyConfig::New(); + std::string base_url = proxy_test_server.base_url().spec(); + // Remove slash from URL. + base_url.pop_back(); + config->rules.ParseFromString("http=" + base_url); + config->pre_cache_headers.SetHeader("foo", "foo_value"); + config->post_cache_headers.SetHeader("bar", "bar_value"); + proxy_config_client->OnCustomProxyConfigUpdated(config->Clone()); + scoped_task_environment_.RunUntilIdle(); + + ResourceRequest request; + request.url = GetURLWithMockHost(test_server, "/echoheadercache?foo&bar"); + std::unique_ptr<TestURLLoaderClient> client = + FetchRequest(request, network_context.get()); + std::string response; + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &response)); + + EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n")); + EXPECT_EQ(client->response_head().proxy_server, + net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP)); + EXPECT_FALSE(client->response_head().was_fetched_via_cache); + + // post_cache_headers should not break caching. + config->post_cache_headers.SetHeader("bar", "new_bar"); + proxy_config_client->OnCustomProxyConfigUpdated(config->Clone()); + scoped_task_environment_.RunUntilIdle(); + + client = FetchRequest(request, network_context.get()); + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &response)); + + EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n")); + EXPECT_TRUE(client->response_head().was_fetched_via_cache); + + // pre_cache_headers should invalidate cache. + config->pre_cache_headers.SetHeader("foo", "new_foo"); + proxy_config_client->OnCustomProxyConfigUpdated(config->Clone()); + scoped_task_environment_.RunUntilIdle(); + + client = FetchRequest(request, network_context.get()); + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &response)); + + EXPECT_EQ(response, base::JoinString({"new_bar", "new_foo"}, "\n")); + EXPECT_EQ(client->response_head().proxy_server, + net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP)); + EXPECT_FALSE(client->response_head().was_fetched_via_cache); +} + +TEST_F(NetworkContextMockHostTest, CustomProxyRequestHeadersAddedBeforeCache) { + net::EmbeddedTestServer test_server; + ASSERT_TRUE(test_server.Start()); + + net::EmbeddedTestServer proxy_test_server; + net::test_server::RegisterDefaultHandlers(&proxy_test_server); + ASSERT_TRUE(proxy_test_server.Start()); + + mojom::CustomProxyConfigClientPtr proxy_config_client; + mojom::NetworkContextParamsPtr context_params = CreateContextParams(); + context_params->custom_proxy_config_client_request = + mojo::MakeRequest(&proxy_config_client); + std::unique_ptr<NetworkContext> network_context = + CreateContextWithParams(std::move(context_params)); + + auto config = mojom::CustomProxyConfig::New(); + std::string base_url = proxy_test_server.base_url().spec(); + // Remove slash from URL. + base_url.pop_back(); + config->rules.ParseFromString("http=" + base_url); + proxy_config_client->OnCustomProxyConfigUpdated(std::move(config)); + scoped_task_environment_.RunUntilIdle(); + + ResourceRequest request; + request.url = GetURLWithMockHost(test_server, "/echoheadercache?foo&bar"); + request.custom_proxy_pre_cache_headers.SetHeader("foo", "foo_value"); + request.custom_proxy_post_cache_headers.SetHeader("bar", "bar_value"); + std::unique_ptr<TestURLLoaderClient> client = + FetchRequest(request, network_context.get()); + std::string response; + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &response)); + + EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n")); + EXPECT_EQ(client->response_head().proxy_server, + net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP)); + EXPECT_FALSE(client->response_head().was_fetched_via_cache); + + // custom_proxy_post_cache_headers should not break caching. + request.custom_proxy_post_cache_headers.SetHeader("bar", "new_bar"); + + client = FetchRequest(request, network_context.get()); + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &response)); + + EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n")); + EXPECT_TRUE(client->response_head().was_fetched_via_cache); + + // custom_proxy_pre_cache_headers should invalidate cache. + request.custom_proxy_pre_cache_headers.SetHeader("foo", "new_foo"); + + client = FetchRequest(request, network_context.get()); + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &response)); + + EXPECT_EQ(response, base::JoinString({"new_bar", "new_foo"}, "\n")); + EXPECT_EQ(client->response_head().proxy_server, + net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP)); + EXPECT_FALSE(client->response_head().was_fetched_via_cache); +} + +TEST_F(NetworkContextMockHostTest, + CustomProxyDoesNotAddHeadersWhenNoProxyUsed) { + net::EmbeddedTestServer test_server; + net::test_server::RegisterDefaultHandlers(&test_server); + ASSERT_TRUE(test_server.Start()); + + mojom::CustomProxyConfigClientPtr proxy_config_client; + mojom::NetworkContextParamsPtr context_params = CreateContextParams(); + context_params->custom_proxy_config_client_request = + mojo::MakeRequest(&proxy_config_client); + std::unique_ptr<NetworkContext> network_context = + CreateContextWithParams(std::move(context_params)); + + auto config = mojom::CustomProxyConfig::New(); + config->pre_cache_headers.SetHeader("pre_foo", "bad"); + config->post_cache_headers.SetHeader("post_foo", "bad"); + proxy_config_client->OnCustomProxyConfigUpdated(std::move(config)); + scoped_task_environment_.RunUntilIdle(); + + ResourceRequest request; + request.custom_proxy_pre_cache_headers.SetHeader("pre_bar", "bad"); + request.custom_proxy_post_cache_headers.SetHeader("post_bar", "bad"); + request.url = GetURLWithMockHost( + test_server, "/echoheader?pre_foo&post_foo&pre_bar&post_bar"); + std::unique_ptr<TestURLLoaderClient> client = + FetchRequest(request, network_context.get()); + std::string response; + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &response)); + + EXPECT_EQ(response, base::JoinString({"None", "None", "None", "None"}, "\n")); + EXPECT_TRUE(client->response_head().proxy_server.is_direct()); +} + +TEST_F(NetworkContextMockHostTest, + CustomProxyDoesNotAddHeadersWhenOtherProxyUsed) { + net::EmbeddedTestServer test_server; + ASSERT_TRUE(test_server.Start()); + + net::EmbeddedTestServer proxy_test_server; + net::test_server::RegisterDefaultHandlers(&proxy_test_server); + ASSERT_TRUE(proxy_test_server.Start()); + + mojom::NetworkContextParamsPtr context_params = CreateContextParams(); + // Set up a proxy to be used by the proxy config service. + net::ProxyConfig proxy_config; + std::string base_url = proxy_test_server.base_url().spec(); + // Remove slash from URL. + base_url.pop_back(); + proxy_config.proxy_rules().ParseFromString("http=" + base_url); + context_params->initial_proxy_config = net::ProxyConfigWithAnnotation( + proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS); + + mojom::CustomProxyConfigClientPtr proxy_config_client; + context_params->custom_proxy_config_client_request = + mojo::MakeRequest(&proxy_config_client); + std::unique_ptr<NetworkContext> network_context = + CreateContextWithParams(std::move(context_params)); + + auto config = mojom::CustomProxyConfig::New(); + config->pre_cache_headers.SetHeader("pre_foo", "bad"); + config->post_cache_headers.SetHeader("post_foo", "bad"); + proxy_config_client->OnCustomProxyConfigUpdated(std::move(config)); + scoped_task_environment_.RunUntilIdle(); + + ResourceRequest request; + request.custom_proxy_pre_cache_headers.SetHeader("pre_bar", "bad"); + request.custom_proxy_post_cache_headers.SetHeader("post_bar", "bad"); + request.url = GetURLWithMockHost( + test_server, "/echoheader?pre_foo&post_foo&pre_bar&post_bar"); + std::unique_ptr<TestURLLoaderClient> client = + FetchRequest(request, network_context.get()); + std::string response; + EXPECT_TRUE( + mojo::BlockingCopyToString(client->response_body_release(), &response)); + + EXPECT_EQ(response, base::JoinString({"None", "None", "None", "None"}, "\n")); + EXPECT_EQ(client->response_head().proxy_server, + net::ProxyServer::FromURI(base_url, net::ProxyServer::SCHEME_HTTP)); +} + } // namespace } // namespace network
diff --git a/services/network/network_service_network_delegate.cc b/services/network/network_service_network_delegate.cc index b07d2ce..b9f1a1b 100644 --- a/services/network/network_service_network_delegate.cc +++ b/services/network/network_service_network_delegate.cc
@@ -7,6 +7,7 @@ #include "services/network/cookie_manager.h" #include "services/network/network_context.h" #include "services/network/network_service.h" +#include "services/network/network_service_proxy_delegate.h" #include "services/network/public/cpp/features.h" #include "services/network/url_loader.h" @@ -24,6 +25,28 @@ NetworkServiceNetworkDelegate::~NetworkServiceNetworkDelegate() = default; +int NetworkServiceNetworkDelegate::OnBeforeStartTransaction( + net::URLRequest* request, + net::CompletionOnceCallback callback, + net::HttpRequestHeaders* headers) { + if (network_context_->proxy_delegate()) { + network_context_->proxy_delegate()->OnBeforeStartTransaction(request, + headers); + } + return net::OK; +} + +void NetworkServiceNetworkDelegate::OnBeforeSendHeaders( + net::URLRequest* request, + const net::ProxyInfo& proxy_info, + const net::ProxyRetryInfoMap& proxy_retry_info, + net::HttpRequestHeaders* headers) { + if (network_context_->proxy_delegate()) { + network_context_->proxy_delegate()->OnBeforeSendHeaders(request, proxy_info, + headers); + } +} + int NetworkServiceNetworkDelegate::OnHeadersReceived( net::URLRequest* request, net::CompletionOnceCallback callback,
diff --git a/services/network/network_service_network_delegate.h b/services/network/network_service_network_delegate.h index 74a5a0d..b4b1bbc0 100644 --- a/services/network/network_service_network_delegate.h +++ b/services/network/network_service_network_delegate.h
@@ -22,6 +22,13 @@ private: // net::NetworkDelegateImpl implementation. + void OnBeforeSendHeaders(net::URLRequest* request, + const net::ProxyInfo& proxy_info, + const net::ProxyRetryInfoMap& proxy_retry_info, + net::HttpRequestHeaders* headers) override; + int OnBeforeStartTransaction(net::URLRequest* request, + net::CompletionOnceCallback callback, + net::HttpRequestHeaders* headers) override; int OnHeadersReceived( net::URLRequest* request, net::CompletionOnceCallback callback,
diff --git a/services/network/network_service_proxy_delegate.cc b/services/network/network_service_proxy_delegate.cc new file mode 100644 index 0000000..105a070 --- /dev/null +++ b/services/network/network_service_proxy_delegate.cc
@@ -0,0 +1,157 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/network_service_proxy_delegate.h" +#include "net/base/url_util.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_util.h" +#include "net/proxy_resolution/proxy_info.h" +#include "services/network/url_loader.h" + +namespace network { +namespace { + +void GetAlternativeProxy(const GURL& url, + const net::ProxyRetryInfoMap& proxy_retry_info, + net::ProxyInfo* result) { + net::ProxyServer resolved_proxy_server = result->proxy_server(); + DCHECK(resolved_proxy_server.is_valid()); + + // Right now, HTTPS proxies are assumed to support quic. If this needs to + // change, add a setting in CustomProxyConfig to control this behavior. + if (!resolved_proxy_server.is_https()) + return; + + net::ProxyInfo alternative_proxy_info; + alternative_proxy_info.UseProxyServer(net::ProxyServer( + net::ProxyServer::SCHEME_QUIC, resolved_proxy_server.host_port_pair())); + alternative_proxy_info.DeprioritizeBadProxies(proxy_retry_info); + + if (alternative_proxy_info.is_empty()) + return; + + result->SetAlternativeProxy(alternative_proxy_info.proxy_server()); +} + +bool ApplyProxyConfigToProxyInfo(const net::ProxyConfig::ProxyRules& rules, + const net::ProxyRetryInfoMap& proxy_retry_info, + const GURL& url, + net::ProxyInfo* proxy_info) { + DCHECK(proxy_info); + if (rules.empty()) + return false; + + rules.Apply(url, proxy_info); + proxy_info->DeprioritizeBadProxies(proxy_retry_info); + return !proxy_info->proxy_server().is_direct(); +} + +// Checks if |target_proxy| is in |proxy_list|. +bool CheckProxyList(const net::ProxyList& proxy_list, + const net::ProxyServer& target_proxy) { + for (const auto& proxy : proxy_list.GetAll()) { + if (proxy.host_port_pair().Equals(target_proxy.host_port_pair())) + return true; + } + return false; +} + +} // namespace + +NetworkServiceProxyDelegate::NetworkServiceProxyDelegate( + mojom::CustomProxyConfigClientRequest config_client_request) + : binding_(this, std::move(config_client_request)) {} + +void NetworkServiceProxyDelegate::OnBeforeStartTransaction( + net::URLRequest* request, + net::HttpRequestHeaders* headers) { + if (!MayProxyURL(request->url())) + return; + + headers->MergeFrom(proxy_config_->pre_cache_headers); + + auto* url_loader = URLLoader::ForRequest(*request); + if (url_loader) { + headers->MergeFrom(url_loader->custom_proxy_pre_cache_headers()); + } +} + +void NetworkServiceProxyDelegate::OnBeforeSendHeaders( + net::URLRequest* request, + const net::ProxyInfo& proxy_info, + net::HttpRequestHeaders* headers) { + auto* url_loader = URLLoader::ForRequest(*request); + if (IsInProxyConfig(proxy_info.proxy_server())) { + headers->MergeFrom(proxy_config_->post_cache_headers); + + if (url_loader) { + headers->MergeFrom(url_loader->custom_proxy_post_cache_headers()); + } + // TODO(crbug.com/721403): This check may be incorrect if a new proxy config + // is set between OnBeforeStartTransaction and here. + } else if (MayProxyURL(request->url())) { + for (const auto& kv : proxy_config_->pre_cache_headers.GetHeaderVector()) { + headers->RemoveHeader(kv.key); + } + + if (url_loader) { + for (const auto& kv : + url_loader->custom_proxy_pre_cache_headers().GetHeaderVector()) { + headers->RemoveHeader(kv.key); + } + } + } +} + +NetworkServiceProxyDelegate::~NetworkServiceProxyDelegate() {} + +void NetworkServiceProxyDelegate::OnResolveProxy( + const GURL& url, + const std::string& method, + const net::ProxyRetryInfoMap& proxy_retry_info, + net::ProxyInfo* result) { + if (!EligibleForProxy(*result, url, method)) + return; + + net::ProxyInfo proxy_info; + if (ApplyProxyConfigToProxyInfo(proxy_config_->rules, proxy_retry_info, url, + &proxy_info)) { + DCHECK(!proxy_info.is_empty() && !proxy_info.is_direct()); + result->OverrideProxyList(proxy_info.proxy_list()); + GetAlternativeProxy(url, proxy_retry_info, result); + } +} + +void NetworkServiceProxyDelegate::OnFallback(const net::ProxyServer& bad_proxy, + int net_error) {} + +void NetworkServiceProxyDelegate::OnCustomProxyConfigUpdated( + mojom::CustomProxyConfigPtr proxy_config) { + DCHECK(proxy_config->rules.empty() || + !proxy_config->rules.proxies_for_http.IsEmpty()); + proxy_config_ = std::move(proxy_config); +} + +bool NetworkServiceProxyDelegate::IsInProxyConfig( + const net::ProxyServer& proxy_server) const { + if (!proxy_server.is_valid() || proxy_server.is_direct()) + return false; + + return CheckProxyList(proxy_config_->rules.proxies_for_http, proxy_server); +} + +bool NetworkServiceProxyDelegate::MayProxyURL(const GURL& url) const { + return url.SchemeIs(url::kHttpScheme) && !proxy_config_->rules.empty() && + !net::IsLocalhost(url); +} + +bool NetworkServiceProxyDelegate::EligibleForProxy( + const net::ProxyInfo& proxy_info, + const GURL& url, + const std::string& method) const { + return proxy_info.is_direct() && proxy_info.proxy_list().size() == 1 && + MayProxyURL(url) && net::HttpUtil::IsMethodIdempotent(method); +} + +} // namespace network
diff --git a/services/network/network_service_proxy_delegate.h b/services/network/network_service_proxy_delegate.h new file mode 100644 index 0000000..1d8fc1c --- /dev/null +++ b/services/network/network_service_proxy_delegate.h
@@ -0,0 +1,70 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_NETWORK_NETWORK_SERVICE_PROXY_DELEGATE_H_ +#define SERVICES_NETWORK_NETWORK_SERVICE_PROXY_DELEGATE_H_ + +#include "base/component_export.h" +#include "base/macros.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "net/base/proxy_delegate.h" +#include "services/network/public/mojom/network_context.mojom.h" + +namespace net { +class HttpRequestHeaders; +class URLRequest; +} // namespace net + +namespace network { + +// NetworkServiceProxyDelegate is used to support the custom proxy +// configuration, which can be set in +// NetworkContextParams.custom_proxy_config_client_request. +class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkServiceProxyDelegate + : public net::ProxyDelegate, + public mojom::CustomProxyConfigClient { + public: + explicit NetworkServiceProxyDelegate( + mojom::CustomProxyConfigClientRequest config_client_request); + ~NetworkServiceProxyDelegate() override; + + // These methods are forwarded from the NetworkDelegate. + void OnBeforeStartTransaction(net::URLRequest* request, + net::HttpRequestHeaders* headers); + void OnBeforeSendHeaders(net::URLRequest* request, + const net::ProxyInfo& proxy_info, + net::HttpRequestHeaders* headers); + + // net::ProxyDelegate implementation: + void OnResolveProxy(const GURL& url, + const std::string& method, + const net::ProxyRetryInfoMap& proxy_retry_info, + net::ProxyInfo* result) override; + void OnFallback(const net::ProxyServer& bad_proxy, int net_error) override; + + private: + // Checks whether |proxy_server| is present in the current proxy config. + bool IsInProxyConfig(const net::ProxyServer& proxy_server) const; + + // Whether the current config may proxy |url|. + bool MayProxyURL(const GURL& url) const; + + // Whether the |url| with current |proxy_info| is eligible to be proxied. + bool EligibleForProxy(const net::ProxyInfo& proxy_info, + const GURL& url, + const std::string& method) const; + + // mojom::CustomProxyConfigClient implementation: + void OnCustomProxyConfigUpdated( + mojom::CustomProxyConfigPtr proxy_config) override; + + mojom::CustomProxyConfigPtr proxy_config_; + mojo::Binding<mojom::CustomProxyConfigClient> binding_; + + DISALLOW_COPY_AND_ASSIGN(NetworkServiceProxyDelegate); +}; + +} // namespace network + +#endif // SERVICES_NETWORK_NETWORK_SERVICE_PROXY_DELEGATE_H_
diff --git a/services/network/network_service_proxy_delegate_unittest.cc b/services/network/network_service_proxy_delegate_unittest.cc new file mode 100644 index 0000000..ddce4b2 --- /dev/null +++ b/services/network/network_service_proxy_delegate_unittest.cc
@@ -0,0 +1,319 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/network_service_proxy_delegate.h" +#include "base/test/scoped_task_environment.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace network { +namespace { + +constexpr char kHttpUrl[] = "http://example.com"; +constexpr char kLocalhost[] = "http://localhost"; +constexpr char kHttpsUrl[] = "https://example.com"; +constexpr char kWebsocketUrl[] = "ws://example.com"; + +} // namespace + +class NetworkServiceProxyDelegateTest : public testing::Test { + public: + NetworkServiceProxyDelegateTest() {} + + void SetUp() override { + context_ = std::make_unique<net::TestURLRequestContext>(true); + context_->Init(); + } + + protected: + std::unique_ptr<NetworkServiceProxyDelegate> CreateDelegate( + mojom::CustomProxyConfigPtr config) { + mojom::CustomProxyConfigClientPtr client; + auto delegate = std::make_unique<NetworkServiceProxyDelegate>( + mojo::MakeRequest(&client)); + client->OnCustomProxyConfigUpdated(std::move(config)); + scoped_task_environment_.RunUntilIdle(); + return delegate; + } + + std::unique_ptr<net::URLRequest> CreateRequest(const GURL& url) { + return context_->CreateRequest(url, net::DEFAULT_PRIORITY, nullptr); + } + + private: + std::unique_ptr<net::TestURLRequestContext> context_; + base::test::ScopedTaskEnvironment scoped_task_environment_; +}; + +TEST_F(NetworkServiceProxyDelegateTest, AddsHeadersBeforeCache) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=proxy"); + config->pre_cache_headers.SetHeader("foo", "bar"); + auto delegate = CreateDelegate(std::move(config)); + + net::HttpRequestHeaders headers; + auto request = CreateRequest(GURL(kHttpUrl)); + delegate->OnBeforeStartTransaction(request.get(), &headers); + + std::string value; + EXPECT_TRUE(headers.GetHeader("foo", &value)); + EXPECT_EQ(value, "bar"); +} + +TEST_F(NetworkServiceProxyDelegateTest, + DoesNotAddHeadersBeforeCacheForLocalhost) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=proxy"); + config->pre_cache_headers.SetHeader("foo", "bar"); + auto delegate = CreateDelegate(std::move(config)); + + net::HttpRequestHeaders headers; + auto request = CreateRequest(GURL(kLocalhost)); + delegate->OnBeforeStartTransaction(request.get(), &headers); + + EXPECT_TRUE(headers.IsEmpty()); +} + +TEST_F(NetworkServiceProxyDelegateTest, DoesNotAddHeadersBeforeCacheForHttps) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=proxy"); + config->pre_cache_headers.SetHeader("foo", "bar"); + auto delegate = CreateDelegate(std::move(config)); + + net::HttpRequestHeaders headers; + auto request = CreateRequest(GURL(kHttpsUrl)); + delegate->OnBeforeStartTransaction(request.get(), &headers); + + EXPECT_TRUE(headers.IsEmpty()); +} + +TEST_F(NetworkServiceProxyDelegateTest, AddsHeadersAfterCache) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=proxy"); + config->post_cache_headers.SetHeader("foo", "bar"); + auto delegate = CreateDelegate(std::move(config)); + + net::HttpRequestHeaders headers; + auto request = CreateRequest(GURL(kHttpUrl)); + net::ProxyInfo info; + info.UsePacString("PROXY proxy"); + delegate->OnBeforeSendHeaders(request.get(), info, &headers); + + std::string value; + EXPECT_TRUE(headers.GetHeader("foo", &value)); + EXPECT_EQ(value, "bar"); +} + +TEST_F(NetworkServiceProxyDelegateTest, + DoesNotAddHeadersAfterCacheForProxyNotInConfig) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=proxy"); + config->post_cache_headers.SetHeader("foo", "bar"); + auto delegate = CreateDelegate(std::move(config)); + + net::HttpRequestHeaders headers; + auto request = CreateRequest(GURL(kHttpUrl)); + net::ProxyInfo info; + info.UsePacString("PROXY other"); + delegate->OnBeforeSendHeaders(request.get(), info, &headers); + + EXPECT_TRUE(headers.IsEmpty()); +} + +TEST_F(NetworkServiceProxyDelegateTest, DoesNotAddHeadersAfterCacheForDirect) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=proxy"); + config->post_cache_headers.SetHeader("foo", "bar"); + auto delegate = CreateDelegate(std::move(config)); + + net::HttpRequestHeaders headers; + auto request = CreateRequest(GURL(kHttpUrl)); + net::ProxyInfo info; + info.UseDirect(); + delegate->OnBeforeSendHeaders(request.get(), info, &headers); + + EXPECT_TRUE(headers.IsEmpty()); +} + +TEST_F(NetworkServiceProxyDelegateTest, + RemovesPreCacheHeadersWhenProxyNotInConfig) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=proxy"); + config->pre_cache_headers.SetHeader("foo", "bar"); + auto delegate = CreateDelegate(std::move(config)); + + net::HttpRequestHeaders headers; + headers.SetHeader("foo", "bar"); + auto request = CreateRequest(GURL(kHttpUrl)); + net::ProxyInfo info; + info.UseDirect(); + delegate->OnBeforeSendHeaders(request.get(), info, &headers); + + EXPECT_TRUE(headers.IsEmpty()); +} + +TEST_F(NetworkServiceProxyDelegateTest, + DoesNotRemoveHeaderForHttpsIfAlreadyExists) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=proxy"); + config->pre_cache_headers.SetHeader("foo", "bad"); + auto delegate = CreateDelegate(std::move(config)); + + net::HttpRequestHeaders headers; + headers.SetHeader("foo", "value"); + auto request = CreateRequest(GURL(kHttpsUrl)); + net::ProxyInfo info; + info.UseDirect(); + delegate->OnBeforeSendHeaders(request.get(), info, &headers); + + std::string value; + EXPECT_TRUE(headers.GetHeader("foo", &value)); + EXPECT_EQ(value, "value"); +} + +TEST_F(NetworkServiceProxyDelegateTest, KeepsPreCacheHeadersWhenProxyInConfig) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=proxy"); + config->pre_cache_headers.SetHeader("foo", "bar"); + auto delegate = CreateDelegate(std::move(config)); + + net::HttpRequestHeaders headers; + headers.SetHeader("foo", "bar"); + auto request = CreateRequest(GURL(kHttpUrl)); + net::ProxyInfo info; + info.UsePacString("PROXY proxy"); + delegate->OnBeforeSendHeaders(request.get(), info, &headers); + + std::string value; + EXPECT_TRUE(headers.GetHeader("foo", &value)); + EXPECT_EQ(value, "bar"); +} + +TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxySuccessHttpProxy) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=foo"); + auto delegate = CreateDelegate(std::move(config)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpUrl), "GET", net::ProxyRetryInfoMap(), + &result); + + net::ProxyList expected_proxy_list; + expected_proxy_list.AddProxyServer( + net::ProxyServer::FromPacString("PROXY foo")); + EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list)); + // HTTP proxies are nto used as alternative QUIC proxies. + EXPECT_FALSE(result.alternative_proxy().is_valid()); +} + +TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxySuccessHttpsProxy) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=https://foo"); + auto delegate = CreateDelegate(std::move(config)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpUrl), "GET", net::ProxyRetryInfoMap(), + &result); + + net::ProxyList expected_proxy_list; + expected_proxy_list.AddProxyServer( + net::ProxyServer::FromPacString("HTTPS foo")); + EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list)); + EXPECT_EQ(result.alternative_proxy(), + net::ProxyServer::FromPacString("QUIC foo")); +} + +TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyLocalhost) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=foo"); + auto delegate = CreateDelegate(std::move(config)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kLocalhost), "GET", net::ProxyRetryInfoMap(), + &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.alternative_proxy().is_valid()); +} + +TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyEmptyConfig) { + auto delegate = CreateDelegate(mojom::CustomProxyConfig::New()); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpUrl), "GET", net::ProxyRetryInfoMap(), + &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.alternative_proxy().is_valid()); +} + +TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyNonIdempotentMethod) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=foo"); + auto delegate = CreateDelegate(std::move(config)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kHttpUrl), "POST", net::ProxyRetryInfoMap(), + &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.alternative_proxy().is_valid()); +} + +TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyWebsocketScheme) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=foo"); + auto delegate = CreateDelegate(std::move(config)); + + net::ProxyInfo result; + result.UseDirect(); + delegate->OnResolveProxy(GURL(kWebsocketUrl), "GET", net::ProxyRetryInfoMap(), + &result); + + EXPECT_TRUE(result.is_direct()); + EXPECT_FALSE(result.alternative_proxy().is_valid()); +} + +TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyDoesNotOverrideExisting) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=foo"); + auto delegate = CreateDelegate(std::move(config)); + + net::ProxyInfo result; + result.UsePacString("PROXY bar"); + delegate->OnResolveProxy(GURL(kHttpUrl), "GET", net::ProxyRetryInfoMap(), + &result); + + net::ProxyList expected_proxy_list; + expected_proxy_list.AddProxyServer( + net::ProxyServer::FromPacString("PROXY bar")); + EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list)); + EXPECT_FALSE(result.alternative_proxy().is_valid()); +} + +TEST_F(NetworkServiceProxyDelegateTest, OnResolveProxyDeprioritizesBadProxies) { + auto config = mojom::CustomProxyConfig::New(); + config->rules.ParseFromString("http=foo,bar"); + auto delegate = CreateDelegate(std::move(config)); + + net::ProxyInfo result; + result.UseDirect(); + net::ProxyRetryInfoMap retry_map; + net::ProxyRetryInfo& info = retry_map["foo:80"]; + info.try_while_bad = false; + info.bad_until = base::TimeTicks::Now() + base::TimeDelta::FromDays(2); + delegate->OnResolveProxy(GURL(kHttpUrl), "GET", retry_map, &result); + + net::ProxyList expected_proxy_list; + expected_proxy_list.AddProxyServer( + net::ProxyServer::FromPacString("PROXY bar")); + EXPECT_TRUE(result.proxy_list().Equals(expected_proxy_list)); +} + +} // namespace network
diff --git a/services/network/p2p/socket.cc b/services/network/p2p/socket.cc index 8c65a4d..8595623f 100644 --- a/services/network/p2p/socket.cc +++ b/services/network/p2p/socket.cc
@@ -67,12 +67,7 @@ : delegate_(delegate), client_(std::move(client)), binding_(this, std::move(socket)), - state_(STATE_UNINITIALIZED), protocol_type_(protocol_type), - send_packets_delayed_total_(0), - send_packets_total_(0), - send_bytes_delayed_max_(0), - send_bytes_delayed_cur_(0), weak_ptr_factory_(this) { binding_.set_connection_error_handler( base::BindOnce(&P2PSocket::OnError, base::Unretained(this)));
diff --git a/services/network/p2p/socket.h b/services/network/p2p/socket.h index f6c42681..099d8b6b 100644 --- a/services/network/p2p/socket.h +++ b/services/network/p2p/socket.h
@@ -150,20 +150,19 @@ Delegate* delegate_; mojom::P2PSocketClientPtr client_; mojo::Binding<mojom::P2PSocket> binding_; - State state_; ProtocolType protocol_type_; private: // Track total delayed packets for calculating how many packets are // delayed by system at the end of call. - uint32_t send_packets_delayed_total_; - uint32_t send_packets_total_; + uint32_t send_packets_delayed_total_ = 0; + uint32_t send_packets_total_ = 0; // Track the maximum of consecutive delayed bytes caused by system's // EWOULDBLOCK. - int32_t send_bytes_delayed_max_; - int32_t send_bytes_delayed_cur_; + int32_t send_bytes_delayed_max_ = 0; + int32_t send_bytes_delayed_cur_ = 0; base::WeakPtrFactory<P2PSocket> weak_ptr_factory_;
diff --git a/services/network/p2p/socket_tcp.cc b/services/network/p2p/socket_tcp.cc index 95d81a34..ba0919b9 100644 --- a/services/network/p2p/socket_tcp.cc +++ b/services/network/p2p/socket_tcp.cc
@@ -53,7 +53,7 @@ buffer(buffer), traffic_annotation(traffic_annotation) {} P2PSocketTcp::SendBuffer::SendBuffer(const SendBuffer& rhs) = default; -P2PSocketTcp::SendBuffer::~SendBuffer() {} +P2PSocketTcp::SendBuffer::~SendBuffer() = default; P2PSocketTcpBase::P2PSocketTcpBase( Delegate* delegate, @@ -62,27 +62,17 @@ P2PSocketType type, ProxyResolvingClientSocketFactory* proxy_resolving_socket_factory) : P2PSocket(delegate, std::move(client), std::move(socket), P2PSocket::TCP), - write_pending_(false), - connected_(false), type_(type), proxy_resolving_socket_factory_(proxy_resolving_socket_factory) {} -P2PSocketTcpBase::~P2PSocketTcpBase() { - if (state_ == STATE_OPEN) { - DCHECK(socket_.get()); - socket_.reset(); - } -} +P2PSocketTcpBase::~P2PSocketTcpBase() = default; void P2PSocketTcpBase::InitAccepted(const net::IPEndPoint& remote_address, std::unique_ptr<net::StreamSocket> socket) { DCHECK(socket); - DCHECK_EQ(state_, STATE_UNINITIALIZED); - remote_address_.ip_address = remote_address; // TODO(ronghuawu): Add FakeSSLServerSocket. socket_ = std::move(socket); - state_ = STATE_OPEN; DoRead(); } @@ -90,10 +80,9 @@ uint16_t min_port, uint16_t max_port, const P2PHostAndIPEndPoint& remote_address) { - DCHECK_EQ(state_, STATE_UNINITIALIZED); + DCHECK(!socket_); remote_address_ = remote_address; - state_ = STATE_CONNECTING; net::HostPortPair dest_host_port_pair; // If there is a domain name, let's try it first, it's required by some proxy @@ -129,7 +118,6 @@ } void P2PSocketTcpBase::OnConnected(int result) { - DCHECK_EQ(state_, STATE_CONNECTING); DCHECK_NE(result, net::ERR_IO_PENDING); if (result != net::OK) { @@ -142,7 +130,6 @@ } void P2PSocketTcpBase::OnOpen() { - state_ = STATE_OPEN; // Setting socket send and receive buffer size. if (net::OK != socket_->SetReceiveBufferSize(kTcpRecvSocketBufferSize)) { LOG(WARNING) << "Failed to set socket receive buffer size to " @@ -157,7 +144,6 @@ if (!DoSendSocketCreateMsg()) return; - DCHECK_EQ(state_, STATE_OPEN); DoRead(); } @@ -326,8 +312,6 @@ } bool P2PSocketTcpBase::HandleReadResult(int result) { - DCHECK_EQ(state_, STATE_OPEN); - if (result < 0) { LOG(ERROR) << "Error when reading from TCP socket: " << result; OnError();
diff --git a/services/network/p2p/socket_tcp.h b/services/network/p2p/socket_tcp.h index bac29f8..1683264 100644 --- a/services/network/p2p/socket_tcp.h +++ b/services/network/p2p/socket_tcp.h
@@ -110,10 +110,10 @@ base::queue<SendBuffer> write_queue_; SendBuffer write_buffer_; - bool write_pending_; + bool write_pending_ = false; - bool connected_; - P2PSocketType type_; + bool connected_ = false; + const P2PSocketType type_; ProxyResolvingClientSocketFactory* proxy_resolving_socket_factory_; DISALLOW_COPY_AND_ASSIGN(P2PSocketTcpBase);
diff --git a/services/network/p2p/socket_tcp_server.cc b/services/network/p2p/socket_tcp_server.cc index 3f9ec13..f1cd384 100644 --- a/services/network/p2p/socket_tcp_server.cc +++ b/services/network/p2p/socket_tcp_server.cc
@@ -32,20 +32,13 @@ accept_callback_(base::BindRepeating(&P2PSocketTcpServer::OnAccepted, base::Unretained(this))) {} -P2PSocketTcpServer::~P2PSocketTcpServer() { - if (state_ == STATE_OPEN) { - DCHECK(socket_.get()); - socket_.reset(); - } -} +P2PSocketTcpServer::~P2PSocketTcpServer() = default; // TODO(guidou): Add support for port range. void P2PSocketTcpServer::Init(const net::IPEndPoint& local_address, uint16_t min_port, uint16_t max_port, const P2PHostAndIPEndPoint& remote_address) { - DCHECK_EQ(state_, STATE_UNINITIALIZED); - int result = socket_->Listen(local_address, kListenBacklog); if (result < 0) { LOG(ERROR) << "Listen() failed: " << result; @@ -62,7 +55,6 @@ } VLOG(1) << "Local address: " << local_address_.ToString(); - state_ = STATE_OPEN; // NOTE: Remote address can be empty as socket is just listening // in this state. client_->SocketCreated(local_address_, remote_address.ip_address);
diff --git a/services/network/p2p/socket_tcp_unittest.cc b/services/network/p2p/socket_tcp_unittest.cc index 6bb7743..0935e1d 100644 --- a/services/network/p2p/socket_tcp_unittest.cc +++ b/services/network/p2p/socket_tcp_unittest.cc
@@ -64,7 +64,6 @@ local_address_ = ParseAddress(kTestLocalIpAddress, kTestPort1); socket_impl_->remote_address_ = dest_; - socket_impl_->state_ = P2PSocket::STATE_CONNECTING; socket_impl_->OnConnected(net::OK); base::RunLoop().RunUntilIdle(); }
diff --git a/services/network/p2p/socket_udp.cc b/services/network/p2p/socket_udp.cc index 388b497..e7609dd6 100644 --- a/services/network/p2p/socket_udp.cc +++ b/services/network/p2p/socket_udp.cc
@@ -66,6 +66,17 @@ return ""; } +std::unique_ptr<net::DatagramServerSocket> DefaultSocketFactory( + net::NetLog* net_log) { + net::UDPServerSocket* socket = + new net::UDPServerSocket(net_log, net::NetLogSource()); +#if defined(OS_WIN) + socket->UseNonBlockingIO(); +#endif + + return base::WrapUnique(socket); +} + } // namespace namespace network { @@ -87,8 +98,7 @@ P2PSocketUdp::PendingPacket::PendingPacket(const PendingPacket& other) = default; - -P2PSocketUdp::PendingPacket::~PendingPacket() {} +P2PSocketUdp::PendingPacket::~PendingPacket() = default; P2PSocketUdp::P2PSocketUdp(Delegate* Delegate, mojom::P2PSocketClientPtr client, @@ -97,9 +107,6 @@ net::NetLog* net_log, const DatagramServerSocketFactory& socket_factory) : P2PSocket(Delegate, std::move(client), std::move(socket), P2PSocket::UDP), - socket_(socket_factory.Run(net_log)), - send_pending_(false), - last_dscp_(net::DSCP_CS0), throttler_(throttler), net_log_(net_log), socket_factory_(socket_factory) {} @@ -114,23 +121,20 @@ std::move(socket), throttler, net_log, - base::Bind(&P2PSocketUdp::DefaultSocketFactory)) {} + base::BindRepeating(&DefaultSocketFactory)) {} -P2PSocketUdp::~P2PSocketUdp() { - if (state_ == STATE_OPEN) { - DCHECK(socket_.get()); - socket_.reset(); - } -} +P2PSocketUdp::~P2PSocketUdp() = default; void P2PSocketUdp::Init(const net::IPEndPoint& local_address, uint16_t min_port, uint16_t max_port, const P2PHostAndIPEndPoint& remote_address) { - DCHECK_EQ(state_, STATE_UNINITIALIZED); + DCHECK(!socket_); DCHECK((min_port == 0 && max_port == 0) || min_port > 0); DCHECK_LE(min_port, max_port); + socket_ = socket_factory_.Run(net_log_); + int result = -1; if (min_port == 0) { result = socket_->Listen(local_address); @@ -177,8 +181,6 @@ } VLOG(1) << "Local address: " << address.ToString(); - state_ = STATE_OPEN; - // NOTE: Remote address will be same as what renderer provided. client_->SocketCreated(address, remote_address.ip_address); @@ -202,8 +204,6 @@ } bool P2PSocketUdp::HandleReadResult(int result) { - DCHECK_EQ(STATE_OPEN, state_); - if (result > 0) { std::vector<int8_t> data(recv_buffer_->data(), recv_buffer_->data() + result); @@ -342,7 +342,7 @@ } // Send next packets if we have them waiting in the buffer. - while (state_ == STATE_OPEN && !send_queue_.empty() && !send_pending_) { + while (!send_queue_.empty() && !send_pending_) { PendingPacket packet = send_queue_.front(); send_queue_.pop_front(); if (!DoSend(packet)) @@ -437,16 +437,4 @@ #endif } -// static -std::unique_ptr<net::DatagramServerSocket> P2PSocketUdp::DefaultSocketFactory( - net::NetLog* net_log) { - net::UDPServerSocket* socket = - new net::UDPServerSocket(net_log, net::NetLogSource()); -#if defined(OS_WIN) - socket->UseNonBlockingIO(); -#endif - - return base::WrapUnique(socket); -} - } // namespace network
diff --git a/services/network/p2p/socket_udp.h b/services/network/p2p/socket_udp.h index 5b65792..39c3fb0 100644 --- a/services/network/p2p/socket_udp.h +++ b/services/network/p2p/socket_udp.h
@@ -104,16 +104,14 @@ int result); int SetSocketDiffServCodePointInternal(net::DiffServCodePoint dscp); - static std::unique_ptr<net::DatagramServerSocket> DefaultSocketFactory( - net::NetLog* net_log); std::unique_ptr<net::DatagramServerSocket> socket_; scoped_refptr<net::IOBuffer> recv_buffer_; net::IPEndPoint recv_address_; base::circular_deque<PendingPacket> send_queue_; - bool send_pending_; - net::DiffServCodePoint last_dscp_; + bool send_pending_ = false; + net::DiffServCodePoint last_dscp_ = net::DSCP_CS0; // Set of peer for which we have received STUN binding request or // response or relay allocation request or response.
diff --git a/services/network/public/cpp/network_ipc_param_traits.h b/services/network/public/cpp/network_ipc_param_traits.h index dcf4964..3e69389 100644 --- a/services/network/public/cpp/network_ipc_param_traits.h +++ b/services/network/public/cpp/network_ipc_param_traits.h
@@ -169,6 +169,8 @@ IPC_STRUCT_TRAITS_MEMBER(upgrade_if_insecure) IPC_STRUCT_TRAITS_MEMBER(is_revalidating) IPC_STRUCT_TRAITS_MEMBER(throttling_profile_id) + IPC_STRUCT_TRAITS_MEMBER(custom_proxy_pre_cache_headers) + IPC_STRUCT_TRAITS_MEMBER(custom_proxy_post_cache_headers) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(network::ResourceResponseInfo)
diff --git a/services/network/public/cpp/proxy_config.typemap b/services/network/public/cpp/proxy_config.typemap index 8f3f5043..4dce13d 100644 --- a/services/network/public/cpp/proxy_config.typemap +++ b/services/network/public/cpp/proxy_config.typemap
@@ -17,7 +17,7 @@ "network.mojom.ProxyBypassRules=net::ProxyBypassRules", "network.mojom.ProxyList=net::ProxyList", "network.mojom.ProxyRulesType=net::ProxyConfig::ProxyRules::Type", - "network.mojom.ProxyRule=net::ProxyConfig::ProxyRule", + "network.mojom.ProxyRules=net::ProxyConfig::ProxyRules", "network.mojom.ProxyConfig=net::ProxyConfig", "network.mojom.ProxyConfigWithAnnotation=net::ProxyConfigWithAnnotation", ]
diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h index e0c40e9..c3c2494 100644 --- a/services/network/public/cpp/resource_request.h +++ b/services/network/public/cpp/resource_request.h
@@ -224,6 +224,12 @@ // The profile ID of network conditions to throttle the network request. base::Optional<base::UnguessableToken> throttling_profile_id; + + // Headers that will be added pre and post cache if the network context uses + // the custom proxy for this request. The custom proxy is used for requests + // that match the custom proxy config, and would otherwise be made direct. + net::HttpRequestHeaders custom_proxy_pre_cache_headers; + net::HttpRequestHeaders custom_proxy_post_cache_headers; }; } // namespace network
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom index 765ac8f..64e4b7f 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom
@@ -30,10 +30,45 @@ import "services/network/public/mojom/url_loader.mojom"; import "services/network/public/mojom/url_loader_factory.mojom"; import "services/network/public/mojom/websocket.mojom"; +import "services/network/public/mojom/http_request_headers.mojom"; import "services/proxy_resolver/public/mojom/proxy_resolver.mojom"; import "url/mojom/origin.mojom"; import "url/mojom/url.mojom"; +// Config for setting a custom proxy config that will be used if a request +// matches the proxy rules and would otherwise be direct. This config allows +// headers to be set on requests to the proxies from the config before and/or +// after the caching layer. Currently only supports proxying http requests. +struct CustomProxyConfig { + // The custom proxy rules to use. Right now this is limited to proxies for + // http requests. + ProxyRules rules; + + // The custom proxy can set these headers in this config which will be added + // to all requests using the proxy. This allows setting headers that may be + // privacy/security sensitive which we don't want to send to the renderer. + // Headers that require per-request logic can be added through the + // |custom_proxy_pre_cache_headers| and |custom_proxy_post_cache_headers| + // fields in ResourceRequest. + // + // Headers that will be set before the cache for http requests. If the request + // does not use a custom proxy, these headers will be removed before sending + // to the network. If a request already has one of these headers set, it may + // be overwritten if a custom proxy is used, or removed if a custom proxy is + // not used. + HttpRequestHeaders pre_cache_headers; + + // Headers that will be set after the cache for requests that are issued + // through a custom proxy. Headers here will overwrite matching headers on the + // request if a custom proxy is used. + HttpRequestHeaders post_cache_headers; +}; + +// Client to update the custom proxy config. +interface CustomProxyConfigClient { + OnCustomProxyConfigUpdated(CustomProxyConfig proxy_config); +}; + // Parameters for constructing a network context. struct NetworkContextParams { // Name used by memory tools to identify the context. @@ -141,6 +176,11 @@ ProxyConfigWithAnnotation? initial_proxy_config; ProxyConfigClient&? proxy_config_client_request; + // If |custom_proxy_config_client_request| is set, this context will listen + // for updates to the custom proxy config, and use it if applicable for + // requests which would otherwise be made direct. + CustomProxyConfigClient&? custom_proxy_config_client_request; + // If |proxy_config_client_request| is non-null, this is called during // periods of network activity, and can be used as a signal for polling-based // logic to determine the proxy config.
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc index 1f85c070..78e3678 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc
@@ -321,6 +321,8 @@ keepalive_statistics_recorder_(std::move(keepalive_statistics_recorder)), network_usage_accumulator_(std::move(network_usage_accumulator)), first_auth_attempt_(true), + custom_proxy_pre_cache_headers_(request.custom_proxy_pre_cache_headers), + custom_proxy_post_cache_headers_(request.custom_proxy_post_cache_headers), weak_ptr_factory_(this) { DCHECK(delete_callback_); if (!base::FeatureList::IsEnabled(features::kNetworkService)) {
diff --git a/services/network/url_loader.h b/services/network/url_loader.h index 1b14cd7..5f30e19 100644 --- a/services/network/url_loader.h +++ b/services/network/url_loader.h
@@ -103,6 +103,14 @@ uint32_t GetRenderFrameId() const; uint32_t GetProcessId() const; + const net::HttpRequestHeaders& custom_proxy_pre_cache_headers() const { + return custom_proxy_pre_cache_headers_; + } + + const net::HttpRequestHeaders& custom_proxy_post_cache_headers() const { + return custom_proxy_post_cache_headers_; + } + // Gets the URLLoader associated with this request. static URLLoader* ForRequest(const net::URLRequest& request); @@ -255,6 +263,9 @@ std::unique_ptr<ScopedThrottlingToken> throttling_token_; + net::HttpRequestHeaders custom_proxy_pre_cache_headers_; + net::HttpRequestHeaders custom_proxy_post_cache_headers_; + base::WeakPtrFactory<URLLoader> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(URLLoader);
diff --git a/services/service_manager/public/cpp/BUILD.gn b/services/service_manager/public/cpp/BUILD.gn index 40125676e..82ae6c8 100644 --- a/services/service_manager/public/cpp/BUILD.gn +++ b/services/service_manager/public/cpp/BUILD.gn
@@ -17,6 +17,8 @@ "local_interface_provider.h", "service.cc", "service.h", + "service_binding.cc", + "service_binding.h", "service_context.cc", "service_context.h", "service_context_ref.cc", @@ -37,7 +39,12 @@ "//url", ] - defines = [ "SERVICE_MANAGER_PUBLIC_CPP_IMPL" ] + defines = [ + "IS_SERVICE_MANAGER_CPP_IMPL", + + # TODO: Use COMPONENT_EXPORT everywhere here and remove this. + "SERVICE_MANAGER_PUBLIC_CPP_IMPL", + ] } # A component for types which the public interfaces depend on for typemapping.
diff --git a/services/service_manager/public/cpp/service.cc b/services/service_manager/public/cpp/service.cc index 2030d03..11e6996 100644 --- a/services/service_manager/public/cpp/service.cc +++ b/services/service_manager/public/cpp/service.cc
@@ -19,6 +19,8 @@ const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) {} +void Service::OnDisconnected() {} + bool Service::OnServiceManagerConnectionLost() { return true; }
diff --git a/services/service_manager/public/cpp/service.h b/services/service_manager/public/cpp/service.h index b0242905..cf17566 100644 --- a/services/service_manager/public/cpp/service.h +++ b/services/service_manager/public/cpp/service.h
@@ -7,9 +7,9 @@ #include <string> +#include "base/component_export.h" #include "base/macros.h" #include "mojo/public/cpp/system/message_pipe.h" -#include "services/service_manager/public/cpp/export.h" namespace service_manager { @@ -18,7 +18,7 @@ // The primary contract between a Service and the Service Manager, receiving // lifecycle notifications and connection requests. -class SERVICE_MANAGER_PUBLIC_CPP_EXPORT Service { +class COMPONENT_EXPORT(SERVICE_MANAGER_CPP) Service { public: Service(); virtual ~Service(); @@ -37,6 +37,14 @@ const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe); + // Called when the Service Manager has stopped tracking this instance. Once + // invoked, no further Service interface methods will be called on this + // Service, and no further communication with the Service Manager is possible. + // + // The Service may continue to operate and service existing client connections + // as it deems appropriate. + virtual void OnDisconnected(); + // Called when the Service Manager has stopped tracking this instance. The // service should use this as a signal to shut down, and in fact its process // may be reaped shortly afterward if applicable. @@ -49,6 +57,9 @@ // // NOTE: This may be called at any time, and once it's been called, none of // the other public Service methods will be invoked by the ServiceContext. + // + // This is ONLY invoked when using a ServiceContext and is therefore + // deprecated. virtual bool OnServiceManagerConnectionLost(); protected: @@ -72,7 +83,7 @@ // TODO(rockot): Remove this. It's here to satisfy a few remaining use cases // where a Service impl is owned by something other than its ServiceContext. -class SERVICE_MANAGER_PUBLIC_CPP_EXPORT ForwardingService : public Service { +class COMPONENT_EXPORT(SERVICE_MANAGER_CPP) ForwardingService : public Service { public: // |target| must outlive this object. explicit ForwardingService(Service* target);
diff --git a/services/service_manager/public/cpp/service_binding.cc b/services/service_manager/public/cpp/service_binding.cc new file mode 100644 index 0000000..cac9eef --- /dev/null +++ b/services/service_manager/public/cpp/service_binding.cc
@@ -0,0 +1,94 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/service_manager/public/cpp/service_binding.h" + +#include <utility> + +#include "base/bind.h" +#include "services/service_manager/public/cpp/service.h" + +#include "base/debug/stack_trace.h" + +namespace service_manager { + +ServiceBinding::ServiceBinding(service_manager::Service* service) + : service_(service), binding_(this) { + DCHECK(service_); +} + +ServiceBinding::ServiceBinding(service_manager::Service* service, + mojom::ServiceRequest request) + : ServiceBinding(service) { + if (request.is_pending()) + Bind(std::move(request)); +} + +ServiceBinding::~ServiceBinding() = default; + +Connector* ServiceBinding::GetConnector() { + if (!connector_) + connector_ = Connector::Create(&pending_connector_request_); + return connector_.get(); +} + +void ServiceBinding::Bind(mojom::ServiceRequest request) { + DCHECK(!is_bound()); + binding_.Bind(std::move(request)); + binding_.set_connection_error_handler(base::BindOnce( + &ServiceBinding::OnConnectionError, base::Unretained(this))); +} + +void ServiceBinding::RequestClose() { + DCHECK(is_bound()); + if (service_control_.is_bound()) { + service_control_->RequestQuit(); + } else { + // It's possible that the service may request closure before receiving the + // initial |OnStart()| event, in which case there is not yet a control + // interface on which to request closure. In that case we defer until + // |OnStart()| is received. + request_closure_on_start_ = true; + } +} + +void ServiceBinding::Close() { + DCHECK(is_bound()); + binding_.Close(); + service_control_.reset(); + connector_.reset(); +} + +void ServiceBinding::OnConnectionError() { + service_->OnDisconnected(); +} + +void ServiceBinding::OnStart(const Identity& identity, + OnStartCallback callback) { + identity_ = identity; + service_->OnStart(); + + if (!pending_connector_request_.is_pending()) + connector_ = Connector::Create(&pending_connector_request_); + std::move(callback).Run(std::move(pending_connector_request_), + mojo::MakeRequest(&service_control_)); + + // Execute any prior |RequestClose()| request on the service's behalf. + if (request_closure_on_start_) + service_control_->RequestQuit(); +} + +void ServiceBinding::OnBindInterface( + const BindSourceInfo& source_info, + const std::string& interface_name, + mojo::ScopedMessagePipeHandle interface_pipe, + OnBindInterfaceCallback callback) { + // Acknowledge this request. + std::move(callback).Run(); + + service_->OnBindInterface(source_info, interface_name, + std::move(interface_pipe)); +} + +} // namespace service_manager
diff --git a/services/service_manager/public/cpp/service_binding.h b/services/service_manager/public/cpp/service_binding.h new file mode 100644 index 0000000..6ed9548 --- /dev/null +++ b/services/service_manager/public/cpp/service_binding.h
@@ -0,0 +1,139 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_SERVICE_BINDING_H_ +#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_SERVICE_BINDING_H_ + +#include <memory> + +#include "base/callback.h" +#include "base/component_export.h" +#include "base/macros.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "services/service_manager/public/cpp/connector.h" +#include "services/service_manager/public/mojom/connector.mojom.h" +#include "services/service_manager/public/mojom/service.mojom.h" +#include "services/service_manager/public/mojom/service_control.mojom.h" + +namespace service_manager { + +class Service; + +// Encapsulates service-side bindings to Service Manager interfaces. Namely, +// this helps receive and dispatch Service interface events to a service +// implementation, while also exposing a working Connector interface the service +// can use to make outgoing interface requests. +// +// A ServiceBinding is considered to be "bound" after |Bind()| is invoked with a +// valid ServiceRequest (or the equivalent constructor is used -- see below). +// Upon connection error or an explicit call to |Close()|, the ServiceBinding +// will be considered "unbound" until another call to |Bind()| is made. +// +// NOTE: A well-behaved service should aim to always close its ServiceBinding +// gracefully by calling |RequestClose()|. Closing a ServiceBinding abruptly +// (by either destroying it or explicitly calling |Close()|) introduces inherent +// flakiness into the system unless the Service's |OnDisconnected()| has already +// been invoked, because otherwise the Service Manager may have in-flight +// interface requests directed at your service instance and these will be +// dropped to the dismay of the service instance which issued them. Exceptions +// can reasonably be made for system-wide shutdown situations where even the +// Service Manager itself will be imminently torn down. +class COMPONENT_EXPORT(SERVICE_MANAGER_CPP) ServiceBinding + : public mojom::Service { + public: + // Creates a new ServiceBinding bound to |service|. The service will not + // receive any Service interface calls until |Bind()| is called, but its + // |connector()| is usable immediately upon construction. + // + // |service| is not owned and must outlive this ServiceBinding. + explicit ServiceBinding(service_manager::Service* service); + + // Same as above, but behaves as if |Bind(request)| is also called immediately + // after construction. See below. + ServiceBinding(service_manager::Service* service, + mojom::ServiceRequest request); + + ~ServiceBinding() override; + + bool is_bound() const { return binding_.is_bound(); } + + Identity identity() const { return identity_; } + + // Returns a usable Connector which can make outgoing interface requests + // identifying as the service to which this ServiceBinding is bound. + Connector* GetConnector(); + + // Binds this ServiceBinding to a new ServiceRequest. Once a ServiceBinding + // is bound, its target Service will begin receiving Service events. The + // order of events received is: + // + // - OnStart() exactly once + // - OnIdentityKnown() exactly once + // - OnBindInterface() zero or more times + // + // The target Service will be able to receive these events until this + // ServiceBinding is either unbound or destroyed. + // + // If |request| is invalid, this call does nothing. + // + // Must only be called on an unbound ServiceBinding. + void Bind(mojom::ServiceRequest request); + + // Asks the Service Manager nicely if it's OK for this service instance to + // disappear now. If the Service Manager thinks it's OK, it will sever the + // binding's connection, ultimately triggering an |OnDisconnected()| call on + // the bound Service object. + // + // Must only be called on a bound ServiceBinding. + void RequestClose(); + + // Immediately severs the connection to the Service Manager. No further + // incoming interface requests will be received until this ServiceBinding is + // bound again. Always prefer |RequestClose()| under normal circumstances, + // unless |OnDisconnected()| has already been invoked on the Service. See the + // note in the class documentation above regarding graceful binding closure. + // + // Must only be called on a bound ServiceBinding. + void Close(); + + private: + void OnConnectionError(); + + // mojom::Service: + void OnStart(const Identity& identity, OnStartCallback callback) override; + void OnBindInterface(const BindSourceInfo& source_info, + const std::string& interface_name, + mojo::ScopedMessagePipeHandle interface_pipe, + OnBindInterfaceCallback callback) override; + + // The Service instance to which all incoming events from the Service Manager + // should be directed. Typically this is the object which owns this + // ServiceBinding. + service_manager::Service* const service_; + + // A pending Connector request which will eventually be passed to the Service + // Manager. Created preemptively by every unbound ServiceBinding so that + // |connector()| may begin pipelining outgoing requests even before the + // ServiceBinding is bound to a ServiceRequest. + mojom::ConnectorRequest pending_connector_request_; + + mojo::Binding<mojom::Service> binding_; + Identity identity_; + std::unique_ptr<Connector> connector_; + + // This instance's control interface to the service manager. Note that this + // is unbound and therefore invalid until OnStart() is called. + mojom::ServiceControlAssociatedPtr service_control_; + + // Tracks whether |RequestClose()| has been called at least once prior to + // receiving |OnStart()| on a bound ServiceBinding. This ensures that the + // closure request is actually issued once |OnStart()| is invoked. + bool request_closure_on_start_ = false; + + DISALLOW_COPY_AND_ASSIGN(ServiceBinding); +}; + +} // namespace service_manager + +#endif // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_SERVICE_CONTEXT_H_
diff --git a/services/service_manager/tests/connect/connect_test_package.cc b/services/service_manager/tests/connect/connect_test_package.cc index 45a4cb1..acf9cfff4 100644 --- a/services/service_manager/tests/connect/connect_test_package.cc +++ b/services/service_manager/tests/connect/connect_test_package.cc
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/macros.h" +#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/threading/simple_thread.h" #include "mojo/public/cpp/bindings/binding_set.h" @@ -17,8 +18,7 @@ #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/service.h" -#include "services/service_manager/public/cpp/service_context.h" -#include "services/service_manager/public/cpp/service_runner.h" +#include "services/service_manager/public/cpp/service_binding.h" #include "services/service_manager/public/mojom/service_factory.mojom.h" #include "services/service_manager/tests/connect/connect_test.mojom.h" @@ -74,6 +74,7 @@ registry_.AddInterface<test::mojom::UserIdTest>(base::Bind( &ProvidedService::BindUserIdTestRequest, base::Unretained(this))); } + void OnBindInterface(const BindSourceInfo& source_info, const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) override { @@ -81,6 +82,11 @@ source_info); } + void OnDisconnected() override { + service_binding_.Close(); + run_loop_->Quit(); + } + void BindConnectTestServiceRequest( test::mojom::ConnectTestServiceRequest request, const BindSourceInfo& source_info) { @@ -88,10 +94,11 @@ test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New()); state->connection_remote_name = source_info.identity.name(); state->connection_remote_userid = source_info.identity.user_id(); - state->initialize_local_name = context()->identity().name(); - state->initialize_userid = context()->identity().user_id(); + state->initialize_local_name = service_binding_.identity().name(); + state->initialize_userid = service_binding_.identity().user_id(); - context()->connector()->BindInterface(source_info.identity, &caller_); + service_binding_.GetConnector()->BindInterface(source_info.identity, + &caller_); caller_->ConnectionAccepted(std::move(state)); } @@ -111,7 +118,7 @@ } void GetInstance(GetInstanceCallback callback) override { - std::move(callback).Run(context()->identity().instance()); + std::move(callback).Run(service_binding_.identity().instance()); } // test::mojom::BlockedInterface: @@ -123,12 +130,12 @@ void ConnectToClassAppAsDifferentUser( const service_manager::Identity& target, ConnectToClassAppAsDifferentUserCallback callback) override { - context()->connector()->StartService(target); + service_binding_.GetConnector()->StartService(target); mojom::ConnectResult result; Identity resolved_identity; { base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed); - Connector::TestApi test_api(context()->connector()); + Connector::TestApi test_api(service_binding_.GetConnector()); test_api.SetStartServiceCallback( base::Bind(&QuitLoop, &loop, &result, &resolved_identity)); loop.Run(); @@ -138,8 +145,13 @@ // base::SimpleThread: void Run() override { - ServiceRunner(new ForwardingService(this)).Run( - request_.PassMessagePipe().release().value(), false); + base::MessageLoop message_loop; + base::RunLoop run_loop; + run_loop_ = &run_loop; + service_binding_.Bind(std::move(request_)); + run_loop.Run(); + run_loop_ = nullptr; + caller_.reset(); bindings_.CloseAllBindings(); blocked_bindings_.CloseAllBindings(); @@ -147,10 +159,15 @@ } void OnConnectionError() { - if (bindings_.empty()) - context()->QuitNow(); + if (bindings_.empty()) { + if (service_binding_.is_bound()) + service_binding_.Close(); + run_loop_->Quit(); + } } + base::RunLoop* run_loop_; + service_manager::ServiceBinding service_binding_{this}; const std::string title_; mojom::ServiceRequest request_; test::mojom::ExposedInterfacePtr caller_; @@ -166,8 +183,11 @@ public mojom::ServiceFactory, public test::mojom::ConnectTestService { public: - ConnectTestService() {} - ~ConnectTestService() override {} + ConnectTestService(service_manager::mojom::ServiceRequest request, + base::OnceClosure quit_closure) + : service_binding_(this, std::move(request)), + quit_closure_(std::move(quit_closure)) {} + ~ConnectTestService() override = default; private: // service_manager::Service: @@ -184,15 +204,16 @@ base::Bind(&ConnectTestService::BindConnectTestServiceRequest, base::Unretained(this))); } + void OnBindInterface(const BindSourceInfo& source_info, const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) override { registry_.BindInterface(interface_name, std::move(interface_pipe)); } - bool OnServiceManagerConnectionLost() override { + void OnDisconnected() override { provided_services_.clear(); - return true; + std::move(quit_closure_).Run(); } void BindServiceFactoryRequest(mojom::ServiceFactoryRequest request) { @@ -223,14 +244,16 @@ } void GetInstance(GetInstanceCallback callback) override { - std::move(callback).Run(context()->identity().instance()); + std::move(callback).Run(service_binding_.identity().instance()); } void OnConnectionError() { if (bindings_.empty() && service_factory_bindings_.empty()) - context()->CreateQuitClosure().Run(); + service_binding_.RequestClose(); } + service_manager::ServiceBinding service_binding_; + base::OnceClosure quit_closure_; std::vector<std::unique_ptr<Service>> delegates_; mojo::BindingSet<mojom::ServiceFactory> service_factory_bindings_; BinderRegistry registry_; @@ -243,7 +266,12 @@ } // namespace service_manager MojoResult ServiceMain(MojoHandle service_request_handle) { - service_manager::ServiceRunner runner( - new service_manager::ConnectTestService); - return runner.Run(service_request_handle); + base::MessageLoop message_loop; + base::RunLoop run_loop; + service_manager::ConnectTestService service( + service_manager::mojom::ServiceRequest(mojo::MakeScopedHandle( + mojo::MessagePipeHandle(service_request_handle))), + run_loop.QuitClosure()); + run_loop.Run(); + return MOJO_RESULT_OK; }
diff --git a/services/service_manager/tests/lifecycle/app.cc b/services/service_manager/tests/lifecycle/app.cc index b30a7799..9a930dc 100644 --- a/services/service_manager/tests/lifecycle/app.cc +++ b/services/service_manager/tests/lifecycle/app.cc
@@ -2,11 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "services/service_manager/public/c/main.h" -#include "services/service_manager/public/cpp/service_runner.h" +#include "services/service_manager/public/mojom/service.mojom.h" #include "services/service_manager/tests/lifecycle/app_client.h" MojoResult ServiceMain(MojoHandle service_request_handle) { - service_manager::ServiceRunner runner(new service_manager::test::AppClient); - return runner.Run(service_request_handle); + base::MessageLoop message_loop; + base::RunLoop run_loop; + service_manager::test::AppClient app_client( + service_manager::mojom::ServiceRequest(mojo::MakeScopedHandle( + mojo::MessagePipeHandle(service_request_handle))), + run_loop.QuitClosure()); + run_loop.Run(); + return MOJO_RESULT_OK; }
diff --git a/services/service_manager/tests/lifecycle/app_client.cc b/services/service_manager/tests/lifecycle/app_client.cc index 20804e8..3115341 100644 --- a/services/service_manager/tests/lifecycle/app_client.cc +++ b/services/service_manager/tests/lifecycle/app_client.cc
@@ -6,14 +6,20 @@ #include "base/macros.h" #include "base/run_loop.h" -#include "services/service_manager/public/cpp/service_context.h" +#include "services/service_manager/public/cpp/service_binding.h" namespace service_manager { namespace test { -AppClient::AppClient() { +AppClient::AppClient(service_manager::mojom::ServiceRequest request, + base::OnceClosure quit_closure) + : service_binding_(this, std::move(request)), + quit_closure_(std::move(quit_closure)) { + bindings_.set_connection_error_handler(base::BindRepeating( + &AppClient::LifecycleControlBindingLost, base::Unretained(this))); + registry_.AddInterface<mojom::LifecycleControl>( - base::Bind(&AppClient::Create, base::Unretained(this))); + base::BindRepeating(&AppClient::Create, base::Unretained(this))); } AppClient::~AppClient() {} @@ -24,9 +30,12 @@ registry_.BindInterface(interface_name, std::move(interface_pipe)); } -bool AppClient::OnServiceManagerConnectionLost() { - context()->QuitNow(); - return true; +void AppClient::OnDisconnected() { + DCHECK(service_binding_.is_bound()); + service_binding_.Close(); + + if (quit_closure_) + std::move(quit_closure_).Run(); } void AppClient::Create(mojom::LifecycleControlRequest request) { @@ -38,7 +47,10 @@ } void AppClient::GracefulQuit() { - context()->CreateQuitClosure().Run(); + if (service_binding_.is_bound()) + service_binding_.RequestClose(); + else if (quit_closure_) + std::move(quit_closure_).Run(); } void AppClient::Crash() { @@ -49,14 +61,13 @@ } void AppClient::CloseServiceManagerConnection() { - context()->DisconnectFromServiceManager(); - bindings_.set_connection_error_handler( - base::Bind(&AppClient::BindingLost, base::Unretained(this))); + if (service_binding_.is_bound()) + service_binding_.Close(); } -void AppClient::BindingLost() { - if (bindings_.empty()) - OnServiceManagerConnectionLost(); +void AppClient::LifecycleControlBindingLost() { + if (!service_binding_.is_bound() && bindings_.empty() && quit_closure_) + std::move(quit_closure_).Run(); } } // namespace test
diff --git a/services/service_manager/tests/lifecycle/app_client.h b/services/service_manager/tests/lifecycle/app_client.h index f425446..812a28b2 100644 --- a/services/service_manager/tests/lifecycle/app_client.h +++ b/services/service_manager/tests/lifecycle/app_client.h
@@ -8,11 +8,12 @@ #include <memory> #include "base/bind.h" +#include "base/callback.h" #include "base/macros.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/service.h" -#include "services/service_manager/public/cpp/service_runner.h" +#include "services/service_manager/public/cpp/service_binding.h" #include "services/service_manager/public/mojom/service.mojom.h" #include "services/service_manager/tests/lifecycle/lifecycle_unittest.mojom.h" @@ -22,16 +23,15 @@ class AppClient : public Service, public mojom::LifecycleControl { public: - AppClient(); + explicit AppClient(service_manager::mojom::ServiceRequest request, + base::OnceClosure quit_closure); ~AppClient() override; - void set_runner(ServiceRunner* runner) { runner_ = runner; } - // Service: void OnBindInterface(const BindSourceInfo& source_info, const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) override; - bool OnServiceManagerConnectionLost() override; + void OnDisconnected() override; void Create(mojom::LifecycleControlRequest request); @@ -44,9 +44,11 @@ private: class ServiceImpl; - void BindingLost(); + void LifecycleControlBindingLost(); - ServiceRunner* runner_ = nullptr; + ServiceBinding service_binding_; + base::OnceClosure quit_closure_; + BinderRegistry registry_; mojo::BindingSet<mojom::LifecycleControl> bindings_;
diff --git a/services/service_manager/tests/lifecycle/lifecycle_exe.cc b/services/service_manager/tests/lifecycle/lifecycle_exe.cc index f5ab4cd..92f409f 100644 --- a/services/service_manager/tests/lifecycle/lifecycle_exe.cc +++ b/services/service_manager/tests/lifecycle/lifecycle_exe.cc
@@ -2,11 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "services/service_manager/public/c/main.h" -#include "services/service_manager/public/cpp/service_runner.h" +#include "services/service_manager/public/mojom/service.mojom.h" #include "services/service_manager/tests/lifecycle/app_client.h" MojoResult ServiceMain(MojoHandle service_request_handle) { - service_manager::ServiceRunner runner(new service_manager::test::AppClient); - return runner.Run(service_request_handle); + base::MessageLoop message_loop; + base::RunLoop run_loop; + service_manager::test::AppClient app_client( + service_manager::mojom::ServiceRequest(mojo::MakeScopedHandle( + mojo::MessagePipeHandle(service_request_handle))), + run_loop.QuitClosure()); + run_loop.Run(); + return MOJO_RESULT_OK; }
diff --git a/services/service_manager/tests/lifecycle/lifecycle_unittest.cc b/services/service_manager/tests/lifecycle/lifecycle_unittest.cc index f43e7435..44e6afa 100644 --- a/services/service_manager/tests/lifecycle/lifecycle_unittest.cc +++ b/services/service_manager/tests/lifecycle/lifecycle_unittest.cc
@@ -135,7 +135,6 @@ // test::ServiceTest: void SetUp() override { test::ServiceTest::SetUp(); - InitPackage(); instances_ = TrackInstances(); } void TearDown() override { @@ -147,14 +146,6 @@ return !base::CommandLine::ForCurrentProcess()->HasSwitch("single-process"); } - void InitPackage() { - test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestPackageName); - base::RunLoop loop; - lifecycle.set_connection_error_handler(loop.QuitClosure()); - lifecycle->GracefulQuit(); - loop.Run(); - } - test::mojom::LifecycleControlPtr ConnectTo(const std::string& name) { test::mojom::LifecycleControlPtr lifecycle; connector()->BindInterface(name, &lifecycle);
diff --git a/services/service_manager/tests/lifecycle/package.cc b/services/service_manager/tests/lifecycle/package.cc index ad17e1fb..2d942d3 100644 --- a/services/service_manager/tests/lifecycle/package.cc +++ b/services/service_manager/tests/lifecycle/package.cc
@@ -7,12 +7,12 @@ #include "base/bind.h" #include "base/macros.h" +#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "services/service_manager/public/c/main.h" #include "services/service_manager/public/cpp/binder_registry.h" -#include "services/service_manager/public/cpp/service_context.h" -#include "services/service_manager/public/cpp/service_runner.h" +#include "services/service_manager/public/cpp/service_binding.h" #include "services/service_manager/public/mojom/service_factory.mojom.h" #include "services/service_manager/tests/lifecycle/app_client.h" #include "services/service_manager/tests/lifecycle/lifecycle_unittest.mojom.h" @@ -22,19 +22,20 @@ class PackagedApp : public service_manager::Service, public service_manager::test::mojom::LifecycleControl { public: - PackagedApp( - const base::Closure& service_manager_connection_closed_callback, - const base::Closure& destruct_callback) - : service_manager_connection_closed_callback_( - service_manager_connection_closed_callback), - destruct_callback_(destruct_callback) { - bindings_.set_connection_error_handler(base::Bind(&PackagedApp::BindingLost, - base::Unretained(this))); + PackagedApp(service_manager::mojom::ServiceRequest request, + base::OnceClosure service_manager_connection_closed_callback, + base::OnceClosure destruct_callback) + : service_binding_(this, std::move(request)), + service_manager_connection_closed_callback_( + std::move(service_manager_connection_closed_callback)), + destruct_callback_(std::move(destruct_callback)) { + bindings_.set_connection_error_handler( + base::BindRepeating(&PackagedApp::MaybeQuit, base::Unretained(this))); registry_.AddInterface<service_manager::test::mojom::LifecycleControl>( base::Bind(&PackagedApp::Create, base::Unretained(this))); } - ~PackagedApp() override {} + ~PackagedApp() override = default; private: // service_manager::Service: @@ -44,6 +45,11 @@ registry_.BindInterface(interface_name, std::move(interface_pipe)); } + void OnDisconnected() override { + std::move(service_manager_connection_closed_callback_).Run(); + std::move(destruct_callback_).Run(); + } + void Create(service_manager::test::mojom::LifecycleControlRequest request) { bindings_.AddBinding(this, std::move(request)); } @@ -51,12 +57,7 @@ // LifecycleControl: void Ping(PingCallback callback) override { std::move(callback).Run(); } - void GracefulQuit() override { - service_manager_connection_closed_callback_.Run(); - - // Deletes |this|. - destruct_callback_.Run(); - } + void GracefulQuit() override { service_binding_.RequestClose(); } void Crash() override { // When multiple instances are vended from the same package instance, this @@ -65,50 +66,68 @@ } void CloseServiceManagerConnection() override { - service_manager_connection_closed_callback_.Run(); - context()->QuitNow(); + std::move(service_manager_connection_closed_callback_).Run(); + + if (service_binding_.is_bound()) + service_binding_.Close(); + // This only closed our relationship with the service manager, existing // |bindings_| remain active. + MaybeQuit(); } - void BindingLost() { - if (bindings_.empty()) { - // Deletes |this|. - destruct_callback_.Run(); - } + void MaybeQuit() { + if (service_binding_.is_bound() || !bindings_.empty()) + return; + + // Deletes |this|. + std::move(destruct_callback_).Run(); } + service_manager::ServiceBinding service_binding_; + service_manager::BinderRegistry registry_; mojo::BindingSet<service_manager::test::mojom::LifecycleControl> bindings_; // Run when this object's connection to the service manager is closed. - base::Closure service_manager_connection_closed_callback_; + base::OnceClosure service_manager_connection_closed_callback_; // Run when this object is destructed. - base::Closure destruct_callback_; + base::OnceClosure destruct_callback_; DISALLOW_COPY_AND_ASSIGN(PackagedApp); }; -class Package : public service_manager::ForwardingService, +class Package : public service_manager::Service, public service_manager::mojom::ServiceFactory { public: - Package() : ForwardingService(&app_client_) { + explicit Package(service_manager::mojom::ServiceRequest request, + base::OnceClosure quit_closure) + : service_binding_(this, std::move(request)), + quit_closure_(std::move(quit_closure)), + app_client_(service_manager::mojom::ServiceRequest(), + base::BindOnce(&Package::QuitFromAppClient, + base::Unretained(this))) { registry_.AddInterface<service_manager::mojom::ServiceFactory>( - base::Bind(&Package::Create, base::Unretained(this))); + base::BindRepeating(&Package::Create, base::Unretained(this))); } - ~Package() override {} + + ~Package() override = default; private: - // ForwardingService: + void QuitFromAppClient() { std::move(quit_closure_).Run(); } + + // service_manager::Service: void OnBindInterface(const service_manager::BindSourceInfo& source_info, const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) override { if (!registry_.TryBindInterface(interface_name, &interface_pipe)) { - ForwardingService::OnBindInterface(source_info, interface_name, - std::move(interface_pipe)); + app_client_.OnBindInterface(source_info, interface_name, + std::move(interface_pipe)); } } + void OnDisconnected() override { std::move(quit_closure_).Run(); } + void Create(service_manager::mojom::ServiceFactoryRequest request) { bindings_.AddBinding(this, std::move(request)); } @@ -120,48 +139,35 @@ service_manager::mojom::PIDReceiverPtr pid_receiver) override { ++service_manager_connection_refcount_; int id = next_id_++; - std::unique_ptr<service_manager::ServiceContext> context = - std::make_unique<service_manager::ServiceContext>( - std::make_unique<PackagedApp>( - base::Bind(&Package::AppServiceManagerConnectionClosed, - base::Unretained(this)), - base::Bind(&Package::DestroyService, base::Unretained(this), - id)), - std::move(request)); - service_manager::ServiceContext* raw_context = context.get(); - contexts_.insert(std::make_pair(raw_context, std::move(context))); - id_to_context_.insert(std::make_pair(id, raw_context)); + auto app = std::make_unique<PackagedApp>( + std::move(request), + base::BindOnce(&Package::OnAppInstanceDisconnected, + base::Unretained(this)), + base::BindOnce(&Package::DestroyAppInstance, base::Unretained(this), + id)); + app_instances_.emplace(id, std::move(app)); } - void AppServiceManagerConnectionClosed() { - if (!--service_manager_connection_refcount_) - app_client_.CloseServiceManagerConnection(); + void OnAppInstanceDisconnected() { + if (--service_manager_connection_refcount_ == 0) + service_binding_.RequestClose(); } - void DestroyService(int id) { - auto id_it = id_to_context_.find(id); - DCHECK(id_it != id_to_context_.end()); - - auto it = contexts_.find(id_it->second); - DCHECK(it != contexts_.end()); - contexts_.erase(it); - id_to_context_.erase(id_it); - if (contexts_.empty() && base::RunLoop::IsRunningOnCurrentThread()) - context()->QuitNow(); + void DestroyAppInstance(int id) { + app_instances_.erase(id); + if (app_instances_.empty()) + std::move(quit_closure_).Run(); } + service_manager::ServiceBinding service_binding_; + base::OnceClosure quit_closure_; service_manager::test::AppClient app_client_; int service_manager_connection_refcount_ = 0; service_manager::BinderRegistry registry_; mojo::BindingSet<service_manager::mojom::ServiceFactory> bindings_; - using ServiceContextMap = - std::map<service_manager::ServiceContext*, - std::unique_ptr<service_manager::ServiceContext>>; - ServiceContextMap contexts_; - int next_id_ = 0; - std::map<int, service_manager::ServiceContext*> id_to_context_; + std::map<int, std::unique_ptr<PackagedApp>> app_instances_; DISALLOW_COPY_AND_ASSIGN(Package); }; @@ -169,6 +175,11 @@ } // namespace MojoResult ServiceMain(MojoHandle service_request_handle) { - service_manager::ServiceRunner runner(new Package); - return runner.Run(service_request_handle); + base::MessageLoop message_loop; + base::RunLoop run_loop; + Package package(service_manager::mojom::ServiceRequest(mojo::MakeScopedHandle( + mojo::MessagePipeHandle(service_request_handle))), + run_loop.QuitClosure()); + run_loop.Run(); + return MOJO_RESULT_OK; }
diff --git a/services/viz/public/cpp/compositing/BUILD.gn b/services/viz/public/cpp/compositing/BUILD.gn index 4f61f0a..4b9c524 100644 --- a/services/viz/public/cpp/compositing/BUILD.gn +++ b/services/viz/public/cpp/compositing/BUILD.gn
@@ -47,5 +47,6 @@ "//ui/gfx", "//ui/gfx:test_support", "//ui/gfx/geometry", + "//ui/gfx/geometry/mojo:struct_traits", ] }
diff --git a/services/viz/public/cpp/compositing/transferable_resource.typemap b/services/viz/public/cpp/compositing/transferable_resource.typemap index d286183..e41b212 100644 --- a/services/viz/public/cpp/compositing/transferable_resource.typemap +++ b/services/viz/public/cpp/compositing/transferable_resource.typemap
@@ -14,4 +14,5 @@ type_mappings = [ "viz.mojom.TransferableResource=viz::TransferableResource" ] deps = [ "//gpu/ipc/common:struct_traits", + "//ui/gfx/geometry/mojo:struct_traits", ]
diff --git a/services/ws/gpu_host/BUILD.gn b/services/ws/gpu_host/BUILD.gn index 51401a3..a7cb7eb 100644 --- a/services/ws/gpu_host/BUILD.gn +++ b/services/ws/gpu_host/BUILD.gn
@@ -4,8 +4,6 @@ source_set("gpu_host") { sources = [ - "gpu_client.cc", - "gpu_client.h", "gpu_host.cc", "gpu_host.h", "gpu_host_delegate.h", @@ -19,8 +17,10 @@ "//components/viz/service/main", # TODO(sad): Temporary until GPU process split. "//gpu/command_buffer/client", "//gpu/command_buffer/client:gles2_interface", + "//gpu/command_buffer/service", "//gpu/ipc/client", "//gpu/ipc/common", + "//gpu/ipc/host", "//mojo/public/cpp/bindings", "//mojo/public/cpp/system", "//services/service_manager/public/cpp", @@ -51,6 +51,23 @@ ] } +source_set("test_support") { + testonly = true + + sources = [ + "gpu_host_test_api.cc", + "gpu_host_test_api.h", + ] + + deps = [ + ":gpu_host", + "//base", + "//components/viz/host", + "//components/viz/test:test_support", + "//services/viz/privileged/interfaces", + ] +} + source_set("tests") { testonly = true @@ -60,6 +77,7 @@ deps = [ ":gpu_host", + ":test_support", "//base", "//base/test:test_config", "//base/test:test_support",
diff --git a/services/ws/gpu_host/DEPS b/services/ws/gpu_host/DEPS index e9b718d3..988a583 100644 --- a/services/ws/gpu_host/DEPS +++ b/services/ws/gpu_host/DEPS
@@ -2,10 +2,13 @@ "+base", "+components/viz/common", "+components/viz/host", + "+components/viz/test", "+gpu/command_buffer/client", + "+gpu/command_buffer/service/gpu_switches.h", "+gpu/config", "+gpu/ipc/client", "+gpu/ipc/common", + "+gpu/ipc/host", "+mojo/public", "+services/viz/privileged/interfaces", "+services/viz/public/interfaces",
diff --git a/services/ws/gpu_host/gpu_client.cc b/services/ws/gpu_host/gpu_client.cc deleted file mode 100644 index 0c9d9190..0000000 --- a/services/ws/gpu_host/gpu_client.cc +++ /dev/null
@@ -1,96 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/ws/gpu_host/gpu_client.h" - -#include "components/viz/host/host_gpu_memory_buffer_manager.h" -#include "services/viz/privileged/interfaces/gl/gpu_service.mojom.h" - -namespace ws { -namespace gpu_host { - -GpuClient::GpuClient(int client_id, - gpu::GPUInfo* gpu_info, - gpu::GpuFeatureInfo* gpu_feature_info, - viz::HostGpuMemoryBufferManager* gpu_memory_buffer_manager, - viz::mojom::GpuService* gpu_service) - : client_id_(client_id), - gpu_info_(gpu_info), - gpu_feature_info_(gpu_feature_info), - gpu_memory_buffer_manager_(gpu_memory_buffer_manager), - gpu_service_(gpu_service), - weak_factory_(this) { - DCHECK(gpu_memory_buffer_manager_); - DCHECK(gpu_service_); -} - -GpuClient::~GpuClient() { - gpu_memory_buffer_manager_->DestroyAllGpuMemoryBufferForClient(client_id_); - if (!establish_callback_.is_null()) { - std::move(establish_callback_) - .Run(client_id_, mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(), - gpu::GpuFeatureInfo()); - } -} - -void GpuClient::OnGpuChannelEstablished( - mojo::ScopedMessagePipeHandle channel_handle) { - base::ResetAndReturn(&establish_callback_) - .Run(client_id_, std::move(channel_handle), *gpu_info_, - *gpu_feature_info_); -} - -// mojom::Gpu overrides: -void GpuClient::EstablishGpuChannel(EstablishGpuChannelCallback callback) { - // TODO(sad): https://crbug.com/617415 figure out how to generate a meaningful - // tracing id. - const uint64_t client_tracing_id = 0; - constexpr bool is_gpu_host = false; - if (!establish_callback_.is_null()) { - std::move(establish_callback_) - .Run(client_id_, mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(), - gpu::GpuFeatureInfo()); - } - establish_callback_ = std::move(callback); - const bool cache_shaders_on_disk = true; - gpu_service_->EstablishGpuChannel( - client_id_, client_tracing_id, is_gpu_host, cache_shaders_on_disk, - base::Bind(&GpuClient::OnGpuChannelEstablished, - weak_factory_.GetWeakPtr())); -} - -void GpuClient::CreateJpegDecodeAccelerator( - media::mojom::JpegDecodeAcceleratorRequest jda_request) { - gpu_service_->CreateJpegDecodeAccelerator(std::move(jda_request)); -} - -void GpuClient::CreateVideoEncodeAcceleratorProvider( - media::mojom::VideoEncodeAcceleratorProviderRequest request) { - gpu_service_->CreateVideoEncodeAcceleratorProvider(std::move(request)); -} - -void GpuClient::CreateGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - mojom::GpuMemoryBufferFactory::CreateGpuMemoryBufferCallback callback) { - gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer( - id, client_id_, size, format, usage, gpu::kNullSurfaceHandle, - std::move(callback)); -} - -void GpuClient::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, - const gpu::SyncToken& sync_token) { - gpu_memory_buffer_manager_->DestroyGpuMemoryBuffer(id, client_id_, - sync_token); -} - -void GpuClient::CreateGpuMemoryBufferFactory( - mojom::GpuMemoryBufferFactoryRequest request) { - gpu_memory_buffer_factory_bindings_.AddBinding(this, std::move(request)); -} - -} // namespace gpu_host -} // namespace ws
diff --git a/services/ws/gpu_host/gpu_client.h b/services/ws/gpu_host/gpu_client.h deleted file mode 100644 index a4507d08..0000000 --- a/services/ws/gpu_host/gpu_client.h +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_WS_GPU_HOST_GPU_CLIENT_H_ -#define SERVICES_WS_GPU_HOST_GPU_CLIENT_H_ - -#include "base/memory/weak_ptr.h" -#include "gpu/config/gpu_feature_info.h" -#include "gpu/config/gpu_info.h" -#include "mojo/public/cpp/bindings/binding_set.h" -#include "services/ws/public/mojom/gpu.mojom.h" - -namespace viz { -namespace mojom { -class GpuService; -} // namespace mojom - -class HostGpuMemoryBufferManager; -} // namespace viz - -namespace ws { -namespace gpu_host { - -namespace test { -class GpuHostTest; -} // namespace test - -// The implementation that relays requests from clients to the real -// service implementation in the GPU process over mojom.GpuService. -class GpuClient : public mojom::GpuMemoryBufferFactory, public mojom::Gpu { - public: - GpuClient(int client_id, - gpu::GPUInfo* gpu_info, - gpu::GpuFeatureInfo* gpu_feature_info, - viz::HostGpuMemoryBufferManager* gpu_memory_buffer_manager, - viz::mojom::GpuService* gpu_service); - ~GpuClient() override; - - private: - friend class test::GpuHostTest; - - // EstablishGpuChannelCallback: - void OnGpuChannelEstablished(mojo::ScopedMessagePipeHandle channel_handle); - - // mojom::GpuMemoryBufferFactory overrides: - void CreateGpuMemoryBuffer( - gfx::GpuMemoryBufferId id, - const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - mojom::GpuMemoryBufferFactory::CreateGpuMemoryBufferCallback callback) - override; - void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, - const gpu::SyncToken& sync_token) override; - - // mojom::Gpu overrides: - void CreateGpuMemoryBufferFactory( - mojom::GpuMemoryBufferFactoryRequest request) override; - void EstablishGpuChannel(EstablishGpuChannelCallback callback) override; - void CreateJpegDecodeAccelerator( - media::mojom::JpegDecodeAcceleratorRequest jda_request) override; - void CreateVideoEncodeAcceleratorProvider( - media::mojom::VideoEncodeAcceleratorProviderRequest vea_provider_request) - override; - - const int client_id_; - mojo::BindingSet<mojom::GpuMemoryBufferFactory> - gpu_memory_buffer_factory_bindings_; - - // The objects these pointers refer to are owned by the GpuHost object. - const gpu::GPUInfo* gpu_info_; - const gpu::GpuFeatureInfo* gpu_feature_info_; - viz::HostGpuMemoryBufferManager* gpu_memory_buffer_manager_; - viz::mojom::GpuService* gpu_service_; - EstablishGpuChannelCallback establish_callback_; - - base::WeakPtrFactory<GpuClient> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(GpuClient); -}; - -} // namespace gpu_host -} // namespace ws - -#endif // SERVICES_WS_GPU_HOST_GPU_CLIENT_H_
diff --git a/services/ws/gpu_host/gpu_host.cc b/services/ws/gpu_host/gpu_host.cc index e66b0f1f..a95e967 100644 --- a/services/ws/gpu_host/gpu_host.cc +++ b/services/ws/gpu_host/gpu_host.cc
@@ -11,17 +11,20 @@ #include "components/discardable_memory/service/discardable_shared_memory_manager.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/common/switches.h" +#include "components/viz/host/gpu_client.h" +#include "components/viz/host/gpu_client_delegate.h" #include "components/viz/host/host_gpu_memory_buffer_manager.h" +#include "gpu/command_buffer/service/gpu_switches.h" #include "gpu/ipc/client/gpu_channel_host.h" #include "gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h" #include "gpu/ipc/common/gpu_memory_buffer_support.h" +#include "gpu/ipc/host/shader_disk_cache.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/system/buffer.h" #include "mojo/public/cpp/system/platform_handle.h" #include "services/service_manager/public/cpp/connector.h" #include "services/viz/privileged/interfaces/viz_main.mojom.h" #include "services/viz/public/interfaces/constants.mojom.h" -#include "services/ws/gpu_host/gpu_client.h" #include "services/ws/gpu_host/gpu_host_delegate.h" #include "ui/gfx/buffer_format_util.h" @@ -47,13 +50,46 @@ return base::CommandLine::ForCurrentProcess()->HasSwitch(kEnableViz); } +class GpuClientDelegate : public viz::GpuClientDelegate { + public: + GpuClientDelegate(viz::GpuHostImpl* gpu_host_impl, + viz::HostGpuMemoryBufferManager* gpu_memory_buffer_manager); + ~GpuClientDelegate() override; + + // viz::GpuClientDelegate: + viz::GpuHostImpl* EnsureGpuHost() override; + viz::HostGpuMemoryBufferManager* GetGpuMemoryBufferManager() override; + + private: + viz::GpuHostImpl* gpu_host_impl_; + viz::HostGpuMemoryBufferManager* gpu_memory_buffer_manager_; + + DISALLOW_COPY_AND_ASSIGN(GpuClientDelegate); +}; + +GpuClientDelegate::GpuClientDelegate( + viz::GpuHostImpl* gpu_host_impl, + viz::HostGpuMemoryBufferManager* gpu_memory_buffer_manager) + : gpu_host_impl_(gpu_host_impl), + gpu_memory_buffer_manager_(gpu_memory_buffer_manager) {} + +GpuClientDelegate::~GpuClientDelegate() = default; + +viz::GpuHostImpl* GpuClientDelegate::EnsureGpuHost() { + return gpu_host_impl_; +} + +viz::HostGpuMemoryBufferManager* +GpuClientDelegate::GetGpuMemoryBufferManager() { + return gpu_memory_buffer_manager_; +} + } // namespace -DefaultGpuHost::DefaultGpuHost( - GpuHostDelegate* delegate, - service_manager::Connector* connector, - discardable_memory::DiscardableSharedMemoryManager* - discardable_shared_memory_manager) +GpuHost::GpuHost(GpuHostDelegate* delegate, + service_manager::Connector* connector, + discardable_memory::DiscardableSharedMemoryManager* + discardable_shared_memory_manager) : delegate_(delegate), discardable_shared_memory_manager_(discardable_shared_memory_manager), next_client_id_(kInternalGpuChannelClientId + 1), @@ -71,9 +107,9 @@ // TODO(crbug.com/620927): This should be removed once ozone-mojo is done. gpu_thread_.Start(); gpu_thread_.task_runner()->PostTask( - FROM_HERE, base::BindOnce(&DefaultGpuHost::InitializeVizMain, - base::Unretained(this), - base::Passed(MakeRequest(&viz_main_ptr)))); + FROM_HERE, + base::BindOnce(&GpuHost::InitializeVizMain, base::Unretained(this), + base::Passed(MakeRequest(&viz_main_ptr)))); } else { // Currently, GPU is only run in process in OOP-Ash. NOTREACHED(); @@ -82,7 +118,9 @@ viz::GpuHostImpl::InitParams params; params.restart_id = viz::BeginFrameSource::kNotRestartableId + 1; params.in_process = in_process; - params.disable_gpu_shader_disk_cache = true; + params.disable_gpu_shader_disk_cache = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableGpuShaderDiskCache); params.deadline_to_synchronize_surfaces = switches::GetDeadlineToSynchronizeSurfaces(); params.main_thread_task_runner = main_thread_task_runner_; @@ -92,8 +130,8 @@ #if defined(OS_WIN) // For OS_WIN the process id for GPU is needed. Using GetCurrentProcessId() - // only works with in-process GPU, which is fine because DefaultGpuHost isn't - // used outside of tests. + // only works with in-process GPU, which is fine because GpuHost isn't used + // outside of tests. gpu_host_impl_->OnProcessLaunched(::GetCurrentProcessId()); #endif @@ -107,96 +145,82 @@ gpu_host_impl_->gpu_service()), next_client_id_++, std::make_unique<gpu::GpuMemoryBufferSupport>(), main_thread_task_runner_); + + shader_cache_factory_ = std::make_unique<gpu::ShaderCacheFactory>(); } -DefaultGpuHost::~DefaultGpuHost() { +GpuHost::~GpuHost() { // TODO(crbug.com/620927): This should be removed once ozone-mojo is done. if (gpu_thread_.IsRunning()) { // Stop() will return after |viz_main_impl_| has been destroyed. gpu_thread_.task_runner()->PostTask( - FROM_HERE, base::BindOnce(&DefaultGpuHost::DestroyVizMain, - base::Unretained(this))); + FROM_HERE, + base::BindOnce(&GpuHost::DestroyVizMain, base::Unretained(this))); gpu_thread_.Stop(); } viz::GpuHostImpl::ResetFontRenderParams(); } -void DefaultGpuHost::CreateFrameSinkManager( +void GpuHost::CreateFrameSinkManager( viz::mojom::FrameSinkManagerRequest request, viz::mojom::FrameSinkManagerClientPtrInfo client) { gpu_host_impl_->ConnectFrameSinkManager(std::move(request), std::move(client)); } -void DefaultGpuHost::Shutdown() { +void GpuHost::Shutdown() { gpu_host_impl_.reset(); - gpu_bindings_.CloseAllBindings(); + gpu_clients_.clear(); } -void DefaultGpuHost::Add(mojom::GpuRequest request) { - AddInternal(std::move(request)); -} - -void DefaultGpuHost::OnAcceleratedWidgetAvailable( - gfx::AcceleratedWidget widget) { -#if defined(OS_WIN) - gfx::RenderingWindowManager::GetInstance()->RegisterParent(widget); -#endif -} - -void DefaultGpuHost::OnAcceleratedWidgetDestroyed( - gfx::AcceleratedWidget widget) { -#if defined(OS_WIN) - gfx::RenderingWindowManager::GetInstance()->UnregisterParent(widget); -#endif +void GpuHost::Add(mojom::GpuRequest request) { + const int client_id = next_client_id_++; + const uint64_t client_tracing_id = 0; + auto client = std::make_unique<viz::GpuClient>( + std::make_unique<GpuClientDelegate>(gpu_host_impl_.get(), + gpu_memory_buffer_manager_.get()), + client_id, client_tracing_id, main_thread_task_runner_); + client->Add(std::move(request)); + gpu_clients_.push_back(std::move(client)); } #if defined(OS_CHROMEOS) -void DefaultGpuHost::AddArc(mojom::ArcRequest request) { +void GpuHost::AddArc(mojom::ArcRequest request) { arc_bindings_.AddBinding( std::make_unique<ArcClient>(gpu_host_impl_->gpu_service()), std::move(request)); } #endif // defined(OS_CHROMEOS) -GpuClient* DefaultGpuHost::AddInternal(mojom::GpuRequest request) { - auto client(std::make_unique<GpuClient>( - next_client_id_++, &gpu_info_, &gpu_feature_info_, - gpu_memory_buffer_manager_.get(), gpu_host_impl_->gpu_service())); - GpuClient* client_ref = client.get(); - gpu_bindings_.AddBinding(std::move(client), std::move(request)); - return client_ref; -} - -void DefaultGpuHost::OnBadMessageFromGpu() { +void GpuHost::OnBadMessageFromGpu() { // TODO(sad): Received some unexpected message from the gpu process. We // should kill the process and restart it. NOTIMPLEMENTED(); } -void DefaultGpuHost::InitializeVizMain(viz::mojom::VizMainRequest request) { +void GpuHost::InitializeVizMain(viz::mojom::VizMainRequest request) { viz::VizMainImpl::ExternalDependencies deps; deps.create_display_compositor = true; viz_main_impl_ = std::make_unique<viz::VizMainImpl>(nullptr, std::move(deps)); viz_main_impl_->Bind(std::move(request)); } -void DefaultGpuHost::DestroyVizMain() { +void GpuHost::DestroyVizMain() { DCHECK(viz_main_impl_); viz_main_impl_.reset(); } -gpu::GPUInfo DefaultGpuHost::GetGPUInfo() const { +gpu::GPUInfo GpuHost::GetGPUInfo() const { return gpu_info_; } -gpu::GpuFeatureInfo DefaultGpuHost::GetGpuFeatureInfo() const { +gpu::GpuFeatureInfo GpuHost::GetGpuFeatureInfo() const { return gpu_feature_info_; } -void DefaultGpuHost::DidInitialize( +void GpuHost::DidInitialize( const gpu::GPUInfo& gpu_info, const gpu::GpuFeatureInfo& gpu_feature_info, const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu, @@ -207,45 +231,41 @@ delegate_->OnGpuServiceInitialized(); } -void DefaultGpuHost::DidFailInitialize() {} +void GpuHost::DidFailInitialize() {} -void DefaultGpuHost::DidCreateContextSuccessfully() {} +void GpuHost::DidCreateContextSuccessfully() {} -void DefaultGpuHost::BlockDomainFrom3DAPIs(const GURL& url, - gpu::DomainGuilt guilt) {} +void GpuHost::BlockDomainFrom3DAPIs(const GURL& url, gpu::DomainGuilt guilt) {} -void DefaultGpuHost::DisableGpuCompositing() {} +void GpuHost::DisableGpuCompositing() {} -bool DefaultGpuHost::GpuAccessAllowed() const { - NOTREACHED(); +bool GpuHost::GpuAccessAllowed() const { return true; } -gpu::ShaderCacheFactory* DefaultGpuHost::GetShaderCacheFactory() { - NOTREACHED(); - return nullptr; +gpu::ShaderCacheFactory* GpuHost::GetShaderCacheFactory() { + return shader_cache_factory_.get(); } -void DefaultGpuHost::RecordLogMessage(int32_t severity, - const std::string& header, - const std::string& message) {} +void GpuHost::RecordLogMessage(int32_t severity, + const std::string& header, + const std::string& message) {} -void DefaultGpuHost::BindDiscardableMemoryRequest( +void GpuHost::BindDiscardableMemoryRequest( discardable_memory::mojom::DiscardableSharedMemoryManagerRequest request) { service_manager::BindSourceInfo source_info; discardable_shared_memory_manager_->Bind(std::move(request), source_info); } -void DefaultGpuHost::BindInterface( - const std::string& interface_name, - mojo::ScopedMessagePipeHandle interface_pipe) { +void GpuHost::BindInterface(const std::string& interface_name, + mojo::ScopedMessagePipeHandle interface_pipe) { NOTREACHED(); } #if defined(USE_OZONE) -void DefaultGpuHost::TerminateGpuProcess(const std::string& message) {} +void GpuHost::TerminateGpuProcess(const std::string& message) {} -void DefaultGpuHost::SendGpuProcessMessage(IPC::Message* message) {} +void GpuHost::SendGpuProcessMessage(IPC::Message* message) {} #endif } // namespace gpu_host
diff --git a/services/ws/gpu_host/gpu_host.h b/services/ws/gpu_host/gpu_host.h index d7a9889..d87738e8 100644 --- a/services/ws/gpu_host/gpu_host.h +++ b/services/ws/gpu_host/gpu_host.h
@@ -26,67 +26,48 @@ class DiscardableSharedMemoryManager; } +namespace gpu { +class ShaderCacheFactory; +} + namespace service_manager { class Connector; } namespace viz { +class GpuClient; class GpuHostImpl; class HostGpuMemoryBufferManager; } namespace ws { namespace gpu_host { - -class GpuClient; - -namespace test { -class GpuHostTest; -} // namespace test - class GpuHostDelegate; // GpuHost sets up connection from clients to the real service implementation in // the GPU process. -class GpuHost { +class GpuHost : public viz::GpuHostImpl::Delegate { public: - GpuHost() = default; - virtual ~GpuHost() = default; - - virtual void Add(mojom::GpuRequest request) = 0; - virtual void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) = 0; - virtual void OnAcceleratedWidgetDestroyed(gfx::AcceleratedWidget widget) = 0; - -#if defined(OS_CHROMEOS) - virtual void AddArc(mojom::ArcRequest request) = 0; -#endif // defined(OS_CHROMEOS) -}; - -class DefaultGpuHost : public GpuHost, public viz::GpuHostImpl::Delegate { - public: - DefaultGpuHost(GpuHostDelegate* delegate, - service_manager::Connector* connector, - discardable_memory::DiscardableSharedMemoryManager* - discardable_shared_memory_manager); - ~DefaultGpuHost() override; + GpuHost(GpuHostDelegate* delegate, + service_manager::Connector* connector, + discardable_memory::DiscardableSharedMemoryManager* + discardable_shared_memory_manager); + ~GpuHost() override; void CreateFrameSinkManager(viz::mojom::FrameSinkManagerRequest request, viz::mojom::FrameSinkManagerClientPtrInfo client); void Shutdown(); - // GpuHost: - void Add(mojom::GpuRequest request) override; - void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override; - void OnAcceleratedWidgetDestroyed(gfx::AcceleratedWidget widget) override; + void Add(mojom::GpuRequest request); + #if defined(OS_CHROMEOS) - void AddArc(mojom::ArcRequest request) override; + void AddArc(mojom::ArcRequest request); #endif // defined(OS_CHROMEOS) private: - friend class test::GpuHostTest; + friend class GpuHostTestApi; - GpuClient* AddInternal(mojom::GpuRequest request); void OnBadMessageFromGpu(); // TODO(crbug.com/611505): this goes away after the gpu process split in mus. @@ -132,16 +113,19 @@ std::unique_ptr<viz::HostGpuMemoryBufferManager> gpu_memory_buffer_manager_; + std::unique_ptr<gpu::ShaderCacheFactory> shader_cache_factory_; + + std::vector<std::unique_ptr<viz::GpuClient>> gpu_clients_; + // TODO(crbug.com/620927): This should be removed once ozone-mojo is done. base::Thread gpu_thread_; std::unique_ptr<viz::VizMainImpl> viz_main_impl_; - mojo::StrongBindingSet<mojom::Gpu> gpu_bindings_; #if defined(OS_CHROMEOS) mojo::StrongBindingSet<mojom::Arc> arc_bindings_; #endif // defined(OS_CHROMEOS) - DISALLOW_COPY_AND_ASSIGN(DefaultGpuHost); + DISALLOW_COPY_AND_ASSIGN(GpuHost); }; } // namespace gpu_host
diff --git a/services/ws/gpu_host/gpu_host_test_api.cc b/services/ws/gpu_host/gpu_host_test_api.cc new file mode 100644 index 0000000..a89f9bf --- /dev/null +++ b/services/ws/gpu_host/gpu_host_test_api.cc
@@ -0,0 +1,32 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/ws/gpu_host/gpu_host_test_api.h" + +#include <algorithm> + +#include "components/viz/host/gpu_client.h" +#include "components/viz/test/gpu_host_impl_test_api.h" +#include "services/ws/gpu_host/gpu_host.h" + +namespace ws { +namespace gpu_host { + +GpuHostTestApi::GpuHostTestApi(GpuHost* gpu_host) : gpu_host_(gpu_host) {} + +GpuHostTestApi::~GpuHostTestApi() = default; + +void GpuHostTestApi::SetGpuService(viz::mojom::GpuServicePtr gpu_service) { + return viz::GpuHostImplTestApi(gpu_host_->gpu_host_impl_.get()) + .SetGpuService(std::move(gpu_service)); +} + +base::WeakPtr<viz::GpuClient> GpuHostTestApi::GetLastGpuClient() { + if (gpu_host_->gpu_clients_.empty()) + return nullptr; + return gpu_host_->gpu_clients_.back()->GetWeakPtr(); +} + +} // namespace gpu_host +} // namespace ws
diff --git a/services/ws/gpu_host/gpu_host_test_api.h b/services/ws/gpu_host/gpu_host_test_api.h new file mode 100644 index 0000000..c4a5f60 --- /dev/null +++ b/services/ws/gpu_host/gpu_host_test_api.h
@@ -0,0 +1,36 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_WS_GPU_HOST_GPU_HOST_TEST_API_H_ +#define SERVICES_WS_GPU_HOST_GPU_HOST_TEST_API_H_ + +#include "base/memory/weak_ptr.h" +#include "services/viz/privileged/interfaces/gl/gpu_service.mojom.h" + +namespace viz { +class GpuClient; +} + +namespace ws { +namespace gpu_host { +class GpuHost; + +class GpuHostTestApi { + public: + GpuHostTestApi(GpuHost* gpu_host); + ~GpuHostTestApi(); + + void SetGpuService(viz::mojom::GpuServicePtr gpu_service); + base::WeakPtr<viz::GpuClient> GetLastGpuClient(); + + private: + GpuHost* gpu_host_; + + DISALLOW_COPY_AND_ASSIGN(GpuHostTestApi); +}; + +} // namespace gpu_host +} // namespace ws + +#endif // SERVICES_WS_GPU_HOST_GPU_HOST_TEST_API_H_
diff --git a/services/ws/gpu_host/gpu_host_unittest.cc b/services/ws/gpu_host/gpu_host_unittest.cc index 510c6d9d..a758399 100644 --- a/services/ws/gpu_host/gpu_host_unittest.cc +++ b/services/ws/gpu_host/gpu_host_unittest.cc
@@ -9,11 +9,12 @@ #include "base/message_loop/message_loop.h" #include "base/single_thread_task_runner.h" #include "components/discardable_memory/service/discardable_shared_memory_manager.h" +#include "components/viz/host/gpu_client.h" #include "components/viz/service/gl/gpu_service_impl.h" #include "components/viz/test/gpu_host_impl_test_api.h" #include "gpu/config/gpu_info.h" -#include "services/ws/gpu_host/gpu_client.h" #include "services/ws/gpu_host/gpu_host_delegate.h" +#include "services/ws/gpu_host/gpu_host_test_api.h" #include "services/ws/public/mojom/gpu.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/init/gl_factory.h" @@ -37,7 +38,7 @@ }; // Test implementation of GpuService. For testing behaviour of calls made by -// GpuClient +// viz::GpuClient. class TestGpuService : public viz::GpuServiceImpl { public: explicit TestGpuService( @@ -73,7 +74,7 @@ io_thread_.Stop(); } - base::WeakPtr<GpuClient> AddGpuClient(); + base::WeakPtr<viz::GpuClient> AddGpuClient(); void DestroyHost(); // testing::Test @@ -83,22 +84,20 @@ private: base::MessageLoop message_loop_; - base::WeakPtr<GpuClient> client_ref_; - base::Thread io_thread_; TestGpuHostDelegate gpu_host_delegate_; discardable_memory::DiscardableSharedMemoryManager discardable_memory_manager_; std::unique_ptr<TestGpuService> gpu_service_; viz::mojom::GpuServicePtr gpu_service_ptr_; - std::unique_ptr<DefaultGpuHost> gpu_host_; + std::unique_ptr<GpuHost> gpu_host_; DISALLOW_COPY_AND_ASSIGN(GpuHostTest); }; -base::WeakPtr<GpuClient> GpuHostTest::AddGpuClient() { - GpuClient* client = gpu_host_->AddInternal(mojom::GpuRequest()); - return client->weak_factory_.GetWeakPtr(); +base::WeakPtr<viz::GpuClient> GpuHostTest::AddGpuClient() { + gpu_host_->Add(mojom::GpuRequest()); + return GpuHostTestApi(gpu_host_.get()).GetLastGpuClient(); } void GpuHostTest::DestroyHost() { @@ -107,12 +106,10 @@ void GpuHostTest::SetUp() { testing::Test::SetUp(); - gpu_host_ = std::make_unique<DefaultGpuHost>(&gpu_host_delegate_, nullptr, - &discardable_memory_manager_); - viz::GpuHostImplTestApi test_api(gpu_host_->gpu_host_impl_.get()); - + gpu_host_ = std::make_unique<GpuHost>(&gpu_host_delegate_, nullptr, + &discardable_memory_manager_); gpu_service_->Bind(mojo::MakeRequest(&gpu_service_ptr_)); - test_api.SetGpuService(std::move(gpu_service_ptr_)); + GpuHostTestApi(gpu_host_.get()).SetGpuService(std::move(gpu_service_ptr_)); } void GpuHostTest::TearDown() { @@ -121,18 +118,18 @@ testing::Test::TearDown(); } -// Tests to verify, that if a GpuHost is deleted before GpuClient receives a -// callback, that GpuClient is torn down and does not attempt to use GpuInfo -// after deletion. This should not crash on asan-builds. +// Tests to verify, that if a GpuHost is deleted before viz::GpuClient receives +// a callback, that viz::GpuClient is torn down and does not attempt to use +// GpuInfo after deletion. This should not crash on asan-builds. TEST_F(GpuHostTest, GpuClientDestructionOrder) { - base::WeakPtr<GpuClient> client_ref = AddGpuClient(); + base::WeakPtr<viz::GpuClient> client_ref = AddGpuClient(); EXPECT_NE(nullptr, client_ref); DestroyHost(); EXPECT_EQ(nullptr, client_ref); } TEST_F(GpuHostTest, GpuClientDestroyedWhileChannelRequestInFlight) { - base::WeakPtr<GpuClient> client_ref = AddGpuClient(); + base::WeakPtr<viz::GpuClient> client_ref = AddGpuClient(); mojom::Gpu* gpu = client_ref.get(); bool callback_called = false; gpu->EstablishGpuChannel(
diff --git a/services/ws/public/mojom/BUILD.gn b/services/ws/public/mojom/BUILD.gn index 665702ab..3ab531b 100644 --- a/services/ws/public/mojom/BUILD.gn +++ b/services/ws/public/mojom/BUILD.gn
@@ -70,6 +70,7 @@ "//testing/gtest", "//ui/display/types", "//ui/gfx:test_support", + "//ui/gfx/geometry/mojo:struct_traits", "//ui/gfx/range/mojo:struct_traits", ] }
diff --git a/services/ws/test_ws/test_window_service.cc b/services/ws/test_ws/test_window_service.cc index 70ed107..651066c 100644 --- a/services/ws/test_ws/test_window_service.cc +++ b/services/ws/test_ws/test_window_service.cc
@@ -182,7 +182,7 @@ discardable_shared_memory_manager_ = std::make_unique<discardable_memory::DiscardableSharedMemoryManager>(); - gpu_host_ = std::make_unique<gpu_host::DefaultGpuHost>( + gpu_host_ = std::make_unique<gpu_host::GpuHost>( this, context()->connector(), discardable_shared_memory_manager_.get()); gpu_interface_provider_ = std::make_unique<TestGpuInterfaceProvider>(
diff --git a/services/ws/test_ws/test_window_service.h b/services/ws/test_ws/test_window_service.h index 49773e37..28d8bac 100644 --- a/services/ws/test_ws/test_window_service.h +++ b/services/ws/test_ws/test_window_service.h
@@ -109,7 +109,7 @@ std::unique_ptr<discardable_memory::DiscardableSharedMemoryManager> discardable_shared_memory_manager_; - std::unique_ptr<gpu_host::DefaultGpuHost> gpu_host_; + std::unique_ptr<gpu_host::GpuHost> gpu_host_; // For drag and drop code to convert to/from screen coordinates. wm::DefaultScreenPositionClient screen_position_client_;
diff --git a/storage/browser/blob/blob_data_builder.cc b/storage/browser/blob/blob_data_builder.cc index 4a101542..79b0308 100644 --- a/storage/browser/blob/blob_data_builder.cc +++ b/storage/browser/blob/blob_data_builder.cc
@@ -103,7 +103,6 @@ void BlobDataBuilder::AppendIPCDataElement( const network::DataElement& ipc_data, - const scoped_refptr<FileSystemContext>& file_system_context, const BlobStorageRegistry& blob_registry) { uint64_t length = ipc_data.length(); switch (ipc_data.type()) { @@ -400,22 +399,23 @@ } void BlobDataBuilder::AppendDiskCacheEntry( - const scoped_refptr<DataHandle>& data_handle, + scoped_refptr<DataHandle> data_handle, disk_cache::Entry* disk_cache_entry, int disk_cache_stream_index) { - AppendDiskCacheEntryWithSideData(data_handle, disk_cache_entry, + AppendDiskCacheEntryWithSideData(std::move(data_handle), disk_cache_entry, disk_cache_stream_index, kInvalidDiskCacheSideStreamIndex); } void BlobDataBuilder::AppendDiskCacheEntryWithSideData( - const scoped_refptr<DataHandle>& data_handle, + scoped_refptr<DataHandle> data_handle, disk_cache::Entry* disk_cache_entry, int disk_cache_stream_index, int disk_cache_side_stream_index) { auto item = BlobDataItem::CreateDiskCacheEntry( - 0u, disk_cache_entry->GetDataSize(disk_cache_stream_index), data_handle, - disk_cache_entry, disk_cache_stream_index, disk_cache_side_stream_index); + 0u, disk_cache_entry->GetDataSize(disk_cache_stream_index), + std::move(data_handle), disk_cache_entry, disk_cache_stream_index, + disk_cache_side_stream_index); total_size_ += item->length(); UMA_HISTOGRAM_COUNTS_1M("Storage.BlobItemSize.CacheEntry",
diff --git a/storage/browser/blob/blob_data_builder.h b/storage/browser/blob/blob_data_builder.h index 231223c..35ce853 100644 --- a/storage/browser/blob/blob_data_builder.h +++ b/storage/browser/blob/blob_data_builder.h
@@ -55,12 +55,9 @@ // it's a 'bytes' element. Data elements of BYTES_DESCRIPTION or // DISK_CACHE_ENTRY types are not valid IPC data element types, and cannot be // given to this method. - // |file_system_context| needs to be set if data element is of type - // FILE_FILESYSTEM. // |blob_registry| is needed for data elements of type BLOB. void AppendIPCDataElement( const network::DataElement& ipc_data, - const scoped_refptr<FileSystemContext>& file_system_context, const BlobStorageRegistry& blob_registry); // Copies the given data into the blob. @@ -161,16 +158,15 @@ const base::Time& expected_modification_time, scoped_refptr<FileSystemContext> file_system_context); - void AppendDiskCacheEntry(const scoped_refptr<DataHandle>& data_handle, + void AppendDiskCacheEntry(scoped_refptr<DataHandle> data_handle, disk_cache::Entry* disk_cache_entry, int disk_cache_stream_index); // The content of the side data is accessible with BlobReader::ReadSideData(). - void AppendDiskCacheEntryWithSideData( - const scoped_refptr<DataHandle>& data_handle, - disk_cache::Entry* disk_cache_entry, - int disk_cache_stream_index, - int disk_cache_side_stream_index); + void AppendDiskCacheEntryWithSideData(scoped_refptr<DataHandle> data_handle, + disk_cache::Entry* disk_cache_entry, + int disk_cache_stream_index, + int disk_cache_side_stream_index); void set_content_type(const std::string& content_type) { content_type_ = content_type;
diff --git a/storage/browser/blob/blob_storage_context_unittest.cc b/storage/browser/blob/blob_storage_context_unittest.cc index b94c7c5..e2b3523 100644 --- a/storage/browser/blob/blob_storage_context_unittest.cc +++ b/storage/browser/blob/blob_storage_context_unittest.cc
@@ -483,7 +483,7 @@ ASSERT_TRUE(blob_data_handle2); std::unique_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot(); ASSERT_EQ(1u, data->items().size()); - const scoped_refptr<BlobDataItem> item = data->items()[0]; + BlobDataItem* item = data->items()[0].get(); EXPECT_EQ(kLargeSize - kBlobLength, item->offset()); EXPECT_EQ(kBlobLength, item->length());
diff --git a/storage/browser/blob/blob_transport_strategy.cc b/storage/browser/blob/blob_transport_strategy.cc index f9c40e7..3415f02 100644 --- a/storage/browser/blob/blob_transport_strategy.cc +++ b/storage/browser/blob/blob_transport_strategy.cc
@@ -316,7 +316,7 @@ private: void OnReply(BlobDataBuilder::FutureFile future_file, - const scoped_refptr<ShareableFileReference>& file_reference, + scoped_refptr<ShareableFileReference> file_reference, base::Optional<base::Time> time_file_modified) { if (!time_file_modified) { // Writing to the file failed in the renderer. @@ -325,7 +325,7 @@ } bool populate_result = - future_file.Populate(file_reference, *time_file_modified); + future_file.Populate(std::move(file_reference), *time_file_modified); DCHECK(populate_result); if (--num_unresolved_requests_ == 0)
diff --git a/storage/browser/blob/scoped_file.cc b/storage/browser/blob/scoped_file.cc index a26c7d5..bf25710 100644 --- a/storage/browser/blob/scoped_file.cc +++ b/storage/browser/blob/scoped_file.cc
@@ -19,12 +19,12 @@ ScopedFile::ScopedFile(const base::FilePath& path, ScopeOutPolicy policy, - const scoped_refptr<base::TaskRunner>& file_task_runner) + scoped_refptr<base::TaskRunner> file_task_runner) : path_(path), scope_out_policy_(policy), - file_task_runner_(file_task_runner) { + file_task_runner_(std::move(file_task_runner)) { DCHECK(path.empty() || policy != DELETE_ON_SCOPE_OUT || - file_task_runner.get()) + file_task_runner_.get()) << "path:" << path.value() << " policy:" << policy << " runner:" << file_task_runner.get(); }
diff --git a/storage/browser/blob/scoped_file.h b/storage/browser/blob/scoped_file.h index 4735658..b482ef28 100644 --- a/storage/browser/blob/scoped_file.h +++ b/storage/browser/blob/scoped_file.h
@@ -43,7 +43,7 @@ // is DELETE_ON_SCOPE_OUT. ScopedFile(const base::FilePath& path, ScopeOutPolicy policy, - const scoped_refptr<base::TaskRunner>& file_task_runner); + scoped_refptr<base::TaskRunner> file_task_runner); ScopedFile(ScopedFile&& other); ScopedFile& operator=(ScopedFile&& rhs) {
diff --git a/storage/browser/quota/quota_client.h b/storage/browser/quota/quota_client.h index 61a000585..0b74ba2 100644 --- a/storage/browser/quota/quota_client.h +++ b/storage/browser/quota/quota_client.h
@@ -7,7 +7,6 @@ #include <stdint.h> -#include <list> #include <set> #include <string> @@ -79,9 +78,6 @@ virtual bool DoesSupport(blink::mojom::StorageType type) const = 0; }; -// TODO(dmikurube): Replace it to std::vector for efficiency. -using QuotaClientList = std::list<QuotaClient*>; - } // namespace storage #endif // STORAGE_BROWSER_QUOTA_QUOTA_CLIENT_H_
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc index 11a057a..a4d24bf 100644 --- a/storage/browser/quota/quota_manager.cc +++ b/storage/browser/quota/quota_manager.cc
@@ -813,21 +813,21 @@ QuotaManager::QuotaManager( bool is_incognito, const base::FilePath& profile_path, - const scoped_refptr<base::SingleThreadTaskRunner>& io_thread, - const scoped_refptr<SpecialStoragePolicy>& special_storage_policy, + scoped_refptr<base::SingleThreadTaskRunner> io_thread, + scoped_refptr<SpecialStoragePolicy> special_storage_policy, const GetQuotaSettingsFunc& get_settings_function) : is_incognito_(is_incognito), profile_path_(profile_path), proxy_(new QuotaManagerProxy(this, io_thread)), db_disabled_(false), eviction_disabled_(false), - io_thread_(io_thread), + io_thread_(std::move(io_thread)), db_runner_(base::CreateSequencedTaskRunnerWithTraits( {base::MayBlock(), base::TaskPriority::USER_VISIBLE, base::TaskShutdownBehavior::BLOCK_SHUTDOWN})), get_settings_function_(get_settings_function), is_getting_eviction_origin_(false), - special_storage_policy_(special_storage_policy), + special_storage_policy_(std::move(special_storage_policy)), get_volume_info_fn_(&QuotaManager::GetVolumeInfo), storage_monitor_(new StorageMonitor(this)), weak_factory_(this) {
diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h index 7673368..6489da7 100644 --- a/storage/browser/quota/quota_manager.h +++ b/storage/browser/quota/quota_manager.h
@@ -23,7 +23,6 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" -#include "base/sequenced_task_runner_helpers.h" #include "base/stl_util.h" #include "storage/browser/quota/quota_callbacks.h" #include "storage/browser/quota/quota_client.h" @@ -36,7 +35,6 @@ #include "third_party/blink/public/mojom/quota/quota_types.mojom.h" namespace base { -class FilePath; class SequencedTaskRunner; class SingleThreadTaskRunner; class TaskRunner; @@ -126,12 +124,11 @@ static const int64_t kNoLimit; - QuotaManager( - bool is_incognito, - const base::FilePath& profile_path, - const scoped_refptr<base::SingleThreadTaskRunner>& io_thread, - const scoped_refptr<SpecialStoragePolicy>& special_storage_policy, - const GetQuotaSettingsFunc& get_settings_function); + QuotaManager(bool is_incognito, + const base::FilePath& profile_path, + scoped_refptr<base::SingleThreadTaskRunner> io_thread, + scoped_refptr<SpecialStoragePolicy> special_storage_policy, + const GetQuotaSettingsFunc& get_settings_function); const QuotaSettings& settings() const { return settings_; } void SetQuotaSettings(const QuotaSettings& settings); @@ -452,7 +449,7 @@ GetOriginCallback lru_origin_callback_; std::set<url::Origin> access_notified_origins_; - QuotaClientList clients_; + std::vector<QuotaClient*> clients_; std::unique_ptr<UsageTracker> temporary_usage_tracker_; std::unique_ptr<UsageTracker> persistent_usage_tracker_;
diff --git a/storage/browser/quota/quota_manager_proxy.cc b/storage/browser/quota/quota_manager_proxy.cc index 0125cff..2473ffd 100644 --- a/storage/browser/quota/quota_manager_proxy.cc +++ b/storage/browser/quota/quota_manager_proxy.cc
@@ -154,9 +154,8 @@ QuotaManagerProxy::QuotaManagerProxy( QuotaManager* manager, - const scoped_refptr<base::SingleThreadTaskRunner>& io_thread) - : manager_(manager), io_thread_(io_thread) { -} + scoped_refptr<base::SingleThreadTaskRunner> io_thread) + : manager_(manager), io_thread_(std::move(io_thread)) {} QuotaManagerProxy::~QuotaManagerProxy() = default;
diff --git a/storage/browser/quota/quota_manager_proxy.h b/storage/browser/quota/quota_manager_proxy.h index 32b3292..91ebbf4 100644 --- a/storage/browser/quota/quota_manager_proxy.h +++ b/storage/browser/quota/quota_manager_proxy.h
@@ -66,9 +66,8 @@ friend class QuotaManager; friend class base::RefCountedThreadSafe<QuotaManagerProxy>; - QuotaManagerProxy( - QuotaManager* manager, - const scoped_refptr<base::SingleThreadTaskRunner>& io_thread); + QuotaManagerProxy(QuotaManager* manager, + scoped_refptr<base::SingleThreadTaskRunner> io_thread); virtual ~QuotaManagerProxy(); QuotaManager* manager_; // only accessed on the io thread
diff --git a/storage/browser/quota/usage_tracker.cc b/storage/browser/quota/usage_tracker.cc index 6362317..7530dc64 100644 --- a/storage/browser/quota/usage_tracker.cc +++ b/storage/browser/quota/usage_tracker.cc
@@ -37,7 +37,7 @@ } // namespace -UsageTracker::UsageTracker(const QuotaClientList& clients, +UsageTracker::UsageTracker(const std::vector<QuotaClient*>& clients, blink::mojom::StorageType type, SpecialStoragePolicy* special_storage_policy, StorageMonitor* storage_monitor)
diff --git a/storage/browser/quota/usage_tracker.h b/storage/browser/quota/usage_tracker.h index d03bffd..48f9f0e 100644 --- a/storage/browser/quota/usage_tracker.h +++ b/storage/browser/quota/usage_tracker.h
@@ -11,6 +11,7 @@ #include <memory> #include <set> #include <string> +#include <vector> #include "base/callback.h" #include "base/containers/flat_map.h" @@ -33,7 +34,7 @@ // An instance of this class is created per storage type. class STORAGE_EXPORT UsageTracker : public QuotaTaskObserver { public: - UsageTracker(const QuotaClientList& clients, + UsageTracker(const std::vector<QuotaClient*>& clients, blink::mojom::StorageType type, SpecialStoragePolicy* special_storage_policy, StorageMonitor* storage_monitor);
diff --git a/storage/browser/quota/usage_tracker_unittest.cc b/storage/browser/quota/usage_tracker_unittest.cc index ace109a..4bb6162 100644 --- a/storage/browser/quota/usage_tracker_unittest.cc +++ b/storage/browser/quota/usage_tracker_unittest.cc
@@ -4,6 +4,8 @@ #include <stdint.h> +#include <vector> + #include "base/bind.h" #include "base/location.h" #include "base/macros.h" @@ -19,7 +21,6 @@ using blink::mojom::QuotaStatusCode; using blink::mojom::StorageType; using storage::QuotaClient; -using storage::QuotaClientList; using storage::SpecialStoragePolicy; using storage::UsageTracker; @@ -221,8 +222,8 @@ } private: - QuotaClientList GetUsageTrackerList() { - QuotaClientList client_list; + std::vector<QuotaClient*> GetUsageTrackerList() { + std::vector<QuotaClient*> client_list; client_list.push_back("a_client_); return client_list; }
diff --git a/storage/browser/test/mock_quota_manager.cc b/storage/browser/test/mock_quota_manager.cc index 276ef66..cd26b9d 100644 --- a/storage/browser/test/mock_quota_manager.cc +++ b/storage/browser/test/mock_quota_manager.cc
@@ -6,6 +6,7 @@ #include <limits> #include <memory> +#include <utility> #include "base/location.h" #include "base/memory/ref_counted.h" @@ -33,12 +34,12 @@ MockQuotaManager::MockQuotaManager( bool is_incognito, const base::FilePath& profile_path, - const scoped_refptr<base::SingleThreadTaskRunner>& io_thread, - const scoped_refptr<SpecialStoragePolicy>& special_storage_policy) + scoped_refptr<base::SingleThreadTaskRunner> io_thread, + scoped_refptr<SpecialStoragePolicy> special_storage_policy) : QuotaManager(is_incognito, profile_path, - io_thread, - special_storage_policy, + std::move(io_thread), + std::move(special_storage_policy), storage::GetQuotaSettingsFunc()), weak_factory_(this) {}
diff --git a/storage/browser/test/mock_quota_manager.h b/storage/browser/test/mock_quota_manager.h index 129cb5d..675f4c0 100644 --- a/storage/browser/test/mock_quota_manager.h +++ b/storage/browser/test/mock_quota_manager.h
@@ -42,11 +42,10 @@ // origin data stored in the profile. class MockQuotaManager : public QuotaManager { public: - MockQuotaManager( - bool is_incognito, - const base::FilePath& profile_path, - const scoped_refptr<base::SingleThreadTaskRunner>& io_thread, - const scoped_refptr<SpecialStoragePolicy>& special_storage_policy); + MockQuotaManager(bool is_incognito, + const base::FilePath& profile_path, + scoped_refptr<base::SingleThreadTaskRunner> io_thread, + scoped_refptr<SpecialStoragePolicy> special_storage_policy); // Overrides QuotaManager's implementation. The internal usage data is // updated when MockQuotaManagerProxy::NotifyStorageModified() is
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 75785de..c1266ab2 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -3245,15 +3245,6 @@ "test": "base_unittests" }, { - "args": [ - "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.content_unittests.filter" - ], - "swarming": { - "can_use_on_swarming_builders": true - }, - "test": "content_unittests" - }, - { "swarming": { "can_use_on_swarming_builders": true },
diff --git a/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter index 852719cd..e387f32 100644 --- a/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter +++ b/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter
@@ -109,36 +109,6 @@ # variations::kClientDataHeader in GoogleURLLoaderThrottle. -ChromeResourceDispatcherHostDelegateMirrorBrowserTest.MirrorRequestHeader -# Relies on net::URLRequestMockHTTPJob. --AffiliationCheck/EnterpriseDeviceAttributesTest.Success/Affiliated --AffiliationCheck/EnterpriseDeviceAttributesTest.Success/NotAffiliated --CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/0 --CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/1 --CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/2 --CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/3 --SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/0 --SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/1 --SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/2 --SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/3 --SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/4 --SigninProfileAppsPolicyPerChannelTest.NotWhitelistedAppInstallation/0 --SigninProfileAppsPolicyPerChannelTest.NotWhitelistedAppInstallation/1 --SigninProfileAppsPolicyPerChannelTest.NotWhitelistedAppInstallation/2 --SigninProfileAppsPolicyPerChannelTest.NotWhitelistedAppInstallation/3 --SigninProfileAppsPolicyPerChannelTest.NotWhitelistedAppInstallation/4 --SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/0 --SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/1 --SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/2 --SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/3 --SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/4 --SigninProfileAppsPolicyTest.BackgroundPage --SigninProfileAppsPolicyTest.MultipleApps - -# Navigation blocked by Safe Browsing. -# e.g. Showing 'Your connection is not private' instead of opening 'app.com'. --HostedAppNonClientFrameViewAshTest.FocusableViews/material_refresh --HostedAppNonClientFrameViewAshTest.FocusableViews/material_refresh_touch_optimized - # Flaky with error: `Check failed: (sequence_checker_).CalledOnValidSequence()`. -DevToolsSanityTest.DisposeEmptyBrowserContext
diff --git a/testing/buildbot/filters/webui_polymer2_browser_tests.filter b/testing/buildbot/filters/webui_polymer2_browser_tests.filter index 307ff9d8..80cc817b 100644 --- a/testing/buildbot/filters/webui_polymer2_browser_tests.filter +++ b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
@@ -21,10 +21,6 @@ -MediaRouterElementsBrowserTest.MediaRouterContainerSinkList -MediaRouterElementsBrowserTest.MediaRouterRouteDetails -# Flaky on Windows. See https://crbug.com/881685 -# May also be flaky on Mac/ChromeOS. See https://crbug.com/669227#c10 --MaterialHistoryListTest.All - # Mac only failure. See crbug.com/876990 -CrSettingsPrivacyPageTest.All @@ -34,7 +30,6 @@ -ActiveDirectoryJoinTest.TestActiveDirectoryEnrollment_Success -ActiveDirectoryJoinTest.TestActiveDirectoryEnrollment_UIErrors -CrSettingsFingerprintProgressArcTest.All --CrSettingsMultidevicePageTest.All -CrSettingsPeoplePageLockScreenTest.All -CrSettingsPeoplePageQuickUnlockAuthenticateTest.All -CrSettingsPeoplePageSetupPinDialogTest.All @@ -148,6 +143,7 @@ CrSettingsMultideviceFeatureToggleTest.* CrSettingsMultidevicePageContainerTest.* CrSettingsMultidevicePageTest.* +CrSettingsMultideviceSubpageTest.* CrSettingsNonExistentRouteTest.* CrSettingsOnStartupPageTest.* CrSettingsPaymentsSectionTest.*
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 2b61f2d..8ee2e2edc 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -476,6 +476,10 @@ }, }, 'content_unittests': { + 'remove_from': [ + # chromium.fyi + 'fuchsia-fyi-arm64-rel', # https://crbug.com/881334 + ], 'modifications': { # chromium.memory 'Linux ASan LSan Tests (1)': {
diff --git a/testing/scripts/sizes.py b/testing/scripts/sizes.py index 3713fae..04d264c 100755 --- a/testing/scripts/sizes.py +++ b/testing/scripts/sizes.py
@@ -44,51 +44,19 @@ os.path.join( common.SRC_DIR, 'infra', 'scripts', 'legacy', 'scripts', 'slave', 'chromium', 'sizes.py'), - '--json', tempfile_path + '--failures', tempfile_path ] if args.platform: sizes_cmd.extend(['--platform', args.platform]) rc = common.run_runtest(script_args, runtest_args + sizes_cmd) with open(tempfile_path) as f: - results = json.load(f) - - with open(os.path.join(common.SRC_DIR, 'tools', 'perf_expectations', - 'perf_expectations.json')) as f: - perf_expectations = json.load(f) - - valid = (rc == 0) - failures = [] - - for name, result in results.iteritems(): - fqtn = '%s/%s/%s' % (args.prefix, name, result['identifier']) - if fqtn not in perf_expectations: - continue - - if perf_expectations[fqtn]['type'] != 'absolute': - print 'ERROR: perf expectation %r is not yet supported' % fqtn - valid = False - continue - - actual = result['value'] - expected = perf_expectations[fqtn]['regress'] - better = perf_expectations[fqtn]['better'] - check_result = ((actual <= expected) if better == 'lower' - else (actual >= expected)) - - if not check_result: - failures.append(fqtn) - print 'FAILED %s: actual %s, expected %s, better %s' % ( - fqtn, actual, expected, better) + failures = json.load(f) json.dump({ - 'valid': valid, + 'valid': (rc == 0 or rc == 125), 'failures': failures, }, script_args.output) - # sizes.py itself doesn't fail on regressions. - if failures and rc == 0: - rc = 1 - return rc
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index f0fb225e..167c0ae 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1,4 +1,19 @@ { + "AImageReaderMediaPlayer": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Use_AImageReaderMediaPlayer_V2", + "enable_features": [ + "AImageReaderMediaPlayer" + ] + } + ] + } + ], "AImageReaderVideoOutput": [ { "platforms": [ @@ -2731,24 +2746,6 @@ ] } ], - "NewPrintPreview": [ - { - "platforms": [ - "chromeos", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "NewPrintPreview" - ] - } - ] - } - ], "NewTabInProductHelp": [ { "platforms": [ @@ -4383,10 +4380,13 @@ ], "experiments": [ { - "name": "FinalV6", + "name": "FinalV7", "params": { "variant": "final" - } + }, + "enable_features": [ + "IgnoreTLS13Downgrade" + ] } ] }
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests index 3a65886a..70549451 100644 --- a/third_party/WebKit/LayoutTests/NeverFixTests +++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -1931,5 +1931,8 @@ crbug.com/870172 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ WontFix ] crbug.com/870172 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ WontFix ] +# Tests that only work when the mixed content autoupgrade experiment is enabled +http/tests/mixed-autoupgrade [ WontFix ] + # Not expected to pass in default configuration, only virtual test suite. crbug.com/830901 fast/webgl/video-metadata/texImage-video-last-uploaded-metadata.html [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index d8713be..824960d 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -5218,7 +5218,6 @@ # Sheriff 2018-09-13 crbug.com/883591 [ Android ] fullscreen/full-screen-inline-split-crash.html [ Pass Crash ] -crbug.com/883860 [ Mac ] external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Failure ] crbug.com/883837 [ Win7 ] http/tests/performance-timing/resource_timing_buffer_full_250.html [ Timeout Pass ] # Sheriff 2018-09-18
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites index bebf54bc..d3b07ed8 100644 --- a/third_party/WebKit/LayoutTests/VirtualTestSuites +++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -770,6 +770,21 @@ "args": ["--enable-blink-features=DisplayLocking"] }, { + "prefix" : "autoupgrade-optionally-blockable-mixed-content", + "base": "http/tests/mixed-autoupgrade/optionally", + "args": ["--enable-features=AutoupgradeMixedContent<AU --force-fieldtrials=AU/G1 --force-fieldtrial-params=AU.G1:mode/optionally-blockable"] + }, + { + "prefix" : "autoupgrade-blockable-mixed-content", + "base": "http/tests/mixed-autoupgrade/blockable", + "args": ["--enable-features=AutoupgradeMixedContent<AU --force-fieldtrials=AU/G1 --force-fieldtrial-params=AU.G1:mode/blockable"] + }, + { + "prefix" : "autoupgrade-all-mixed-content", + "base": "http/tests/mixed-autoupgrade/all", + "args": ["--enable-features=AutoupgradeMixedContent"] + }, + { "prefix": "webgl-extra-video-texture-metadata", "base": "fast/webgl/video-metadata", "args": ["--enable-blink-features=ExtraWebGLVideoTextureMetadata"]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-scroll-snap/inheritance-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-scroll-snap/inheritance-expected.txt index 67d9a63..1508689 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/css/css-scroll-snap/inheritance-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-scroll-snap/inheritance-expected.txt
@@ -32,7 +32,7 @@ FAIL Property scroll-padding-top has initial value 0px assert_equals: expected "0px" but got "auto" PASS Property scroll-padding-top does not inherit PASS Property scroll-snap-align has initial value none -FAIL Property scroll-snap-align does not inherit assert_equals: expected "start end" but got "end start" +PASS Property scroll-snap-align does not inherit PASS Property scroll-snap-stop has initial value normal PASS Property scroll-snap-stop does not inherit PASS Property scroll-snap-type has initial value none
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-column-container-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-column-container-expected.html new file mode 100644 index 0000000..acd1b80 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-column-container-expected.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<style> + body { + margin: 0; + height: 4000px; + } + .sticky { + position: absolute; + top: 200px; + } + .columncontainer { + width: 100px; + height: 100px; + background: green; + columns: 1; + } + .contents { + margin-left: 10%; + margin-top: 10%; + width: 80%; + height: 80%; + background: lightgreen; + } +</style> +<script> + function doTest() { + window.scrollTo(0, 100); + } + window.addEventListener('load', doTest, false); +</script> +This test passes if there is a light green square with a dark green border. +<div class="sticky"> + <div class="columncontainer"> + <div class="contents"></div> + </div> +</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-column-container.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-column-container.html new file mode 100644 index 0000000..22b38b6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-column-container.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<style> + body { + margin: 0; + height: 4000px; + } + .sticky { + position: sticky; + top: 100px; + } + .columncontainer { + width: 100px; + height: 100px; + background: green; + columns: 1; + } + .contents { + margin-left: 10%; + margin-top: 10%; + width: 80%; + height: 80%; + background: lightgreen; + } +</style> +<script> + function doTest() { + window.scrollTo(0, 100); + } + window.addEventListener('load', doTest, false); +</script> +This test passes if there is a light green square with a dark green border. +<div class="sticky"> + <div class="columncontainer"> + <div class="contents"></div> + </div> +</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/update-option-label-recalc-root-crash.html b/third_party/WebKit/LayoutTests/fast/css/update-option-label-recalc-root-crash.html new file mode 100644 index 0000000..fcbb579 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/update-option-label-recalc-root-crash.html
@@ -0,0 +1,16 @@ +<!DOCTYPE HTML> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<select> + <option id="opt">Content</option> +</select> +<script> + test(() => { + opt.appendChild(document.createElement("span")); + document.body.offsetTop; + // Mark for style recalc and make the span the recalc root. + opt.lastChild.style.color = "pink"; + // Trigger HTMLOptionElement::UpdateLabel() which removes option UA shadow children. + opt.innerHTML = ""; + }, "Should not cause DCHECK failures or crashes."); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt index 02ea3eb2..274e9566 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt
@@ -24,17 +24,187 @@ Force selecting index 0 Viewport virtual selection: 0 Is group expanded: YES -console-key-expand.js:27 group -console-key-expand.js:27 log child +console-key-expand.js:35 group +console-key-expand.js:35 log child ArrowLeft: Viewport virtual selection: 0 Is group expanded: NO -console-key-expand.js:27 group +console-key-expand.js:35 group ArrowRight: Viewport virtual selection: 0 Is group expanded: YES -console-key-expand.js:27 group -console-key-expand.js:27 log child +console-key-expand.js:35 group +console-key-expand.js:35 log child + +Running: testNavigateBetweenObjectsAndLogs +Evaluating: console.log("before");console.log("text", obj1, obj2);console.log("after"); +Message count: 3 + +Force selecting index 1 +Viewport virtual selection: 1 +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:51 text {x: 1} {y: 2} + +ArrowRight: +Viewport virtual selection: 1 +activeElement: LI.parent.object-properties-section-root-element.selected +active text: {x: 1} + +ArrowDown: +Viewport virtual selection: 1 +activeElement: LI.parent.object-properties-section-root-element.selected +active text: {y: 2} + +ArrowDown: +Viewport virtual selection: 2 +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:51 after + +ArrowUp: +Viewport virtual selection: 1 +activeElement: LI.parent.object-properties-section-root-element.selected +active text: {y: 2} + +ArrowLeft: +Viewport virtual selection: 1 +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:51 text {x: 1} {y: 2} + +Running: testExpandingObjects +Evaluating: console.log("before");console.log("text", obj1, obj2);console.log("after"); +Message count: 3 + +Force selecting index 1 +Viewport virtual selection: 1 +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:70 text {x: 1} {y: 2} + +ArrowRight: +Viewport virtual selection: 1 +activeElement: LI.parent.object-properties-section-root-element.selected +active text: {x: 1} + +ArrowRight: +Viewport virtual selection: 1 +activeElement: LI.parent.object-properties-section-root-element.selected.expanded +active text: {x: 1} + +ArrowDown: +Viewport virtual selection: 1 +activeElement: LI.selected +active text: x: 1 + +ArrowDown: + +ArrowDown: +Viewport virtual selection: 2 +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:70 after + +ArrowRight: +Viewport virtual selection: 2 +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:70 after + +ArrowDown: + +ArrowDown: + +ArrowDown: + +ArrowDown: +Viewport virtual selection: 2 +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:70 after + +ArrowUp: +Viewport virtual selection: 1 +activeElement: LI.parent.object-properties-section-root-element.selected +active text: {y: 2} + +ArrowLeft: +Viewport virtual selection: 1 +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:70 text {x: 1}x: 1 {y: 2}y: 2 + +ArrowLeft: +Viewport virtual selection: 1 +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:70 text {x: 1}x: 1 {y: 2}y: 2 + +Running: testExpandingObjectInTrace +Evaluating: console.log("before");console.warn("warning", obj1);console.log("after"); +Message count: 3 + +Force selecting index 1 +Viewport virtual selection: 1 +Has object: collapsed +Is trace expanded: NO +activeElement: DIV.console-message-wrapper.console-from-api.console-warning-level.console-selected +active text: console-key-expand.js:112 warning {x: 1} +(anonymous) @ console-key-expand.js:112 + +ArrowRight: +Viewport virtual selection: 1 +Has object: collapsed +Is trace expanded: YES +activeElement: DIV.console-message-wrapper.console-from-api.console-warning-level.console-selected +active text: console-key-expand.js:112 warning {x: 1} +(anonymous) @ console-key-expand.js:112 + +ArrowRight: +Viewport virtual selection: 1 +Has object: collapsed +Is trace expanded: YES +activeElement: LI.parent.object-properties-section-root-element.selected +active text: {x: 1} + +ArrowDown: +Viewport virtual selection: 2 +Has object: collapsed +Is trace expanded: YES +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:112 after + +ArrowDown: + +ArrowDown: +Viewport virtual selection: 2 +Has object: collapsed +Is trace expanded: YES +activeElement: DIV.console-message-wrapper.console-from-api.console-info-level.console-selected +active text: console-key-expand.js:112 after + +ArrowUp: +Viewport virtual selection: 1 +Has object: collapsed +Is trace expanded: YES +activeElement: LI.parent.object-properties-section-root-element.selected +active text: {x: 1} + +ArrowUp: +Viewport virtual selection: 1 +Has object: collapsed +Is trace expanded: YES +activeElement: DIV.console-message-wrapper.console-from-api.console-warning-level.console-selected +active text: console-key-expand.js:112 warning {x: 1} +(anonymous) @ console-key-expand.js:112 + +ArrowLeft: +Viewport virtual selection: 1 +Has object: collapsed +Is trace expanded: NO +activeElement: DIV.console-message-wrapper.console-from-api.console-warning-level.console-selected +active text: console-key-expand.js:112 warning {x: 1} +(anonymous) @ console-key-expand.js:112 + +ArrowLeft: +Viewport virtual selection: 1 +Has object: collapsed +Is trace expanded: NO +activeElement: DIV.console-message-wrapper.console-from-api.console-warning-level.console-selected +active text: console-key-expand.js:112 warning {x: 1} +(anonymous) @ console-key-expand.js:112
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand.js index 4ac46ed..8794dc0 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand.js
@@ -13,6 +13,14 @@ const viewport = consoleView._viewport; const prompt = consoleView._prompt; + await TestRunner.evaluateInPagePromise(` + var obj1 = Object.create(null); + obj1.x = 1; + + var obj2 = Object.create(null); + obj2.y = 2; + `); + TestRunner.runTestSuite([ async function testExpandingTraces(next) { await clearAndLog(`console.warn("warning")`); @@ -42,6 +50,101 @@ next(); }, + + async function testNavigateBetweenObjectsAndLogs(next) { + await clearAndLog(`console.log("before");console.log("text", obj1, obj2);console.log("after");`, 3); + forceSelect(1); + + dumpFocus(true, 1, true /* skipObjectCheck */); + press('ArrowRight'); + dumpFocus(true, 1, true /* skipObjectCheck */); + press('ArrowDown'); + dumpFocus(true, 1, true /* skipObjectCheck */); + press('ArrowDown'); + dumpFocus(true, 1, true /* skipObjectCheck */); + press('ArrowUp'); + dumpFocus(true, 1, true /* skipObjectCheck */); + press('ArrowLeft'); + dumpFocus(true, 1, true /* skipObjectCheck */); + + next(); + }, + + async function testExpandingObjects(next) { + await clearAndLog(`console.log("before");console.log("text", obj1, obj2);console.log("after");`, 3); + forceSelect(1); + + dumpFocus(true, 1, true /* skipObjectCheck */); + press('ArrowRight'); + dumpFocus(true, 1, true /* skipObjectCheck */); + + // Expand object. + press('ArrowRight'); + dumpFocus(true, 1, true /* skipObjectCheck */); + await ConsoleTestRunner.waitForRemoteObjectsConsoleMessagesPromise(); + press('ArrowDown'); + dumpFocus(true, 1, true /* skipObjectCheck */); + press('ArrowDown'); + press('ArrowDown'); + dumpFocus(true, 1, true /* skipObjectCheck */); + + // Expand array. + press('ArrowRight'); + dumpFocus(true, 1, true /* skipObjectCheck */); + await ConsoleTestRunner.waitForRemoteObjectsConsoleMessagesPromise(); + press('ArrowDown'); + press('ArrowDown'); + press('ArrowDown'); + press('ArrowDown'); + dumpFocus(true, 1, true /* skipObjectCheck */); + + press('ArrowUp'); + dumpFocus(true, 1, true /* skipObjectCheck */); + + // Collapse object. + press('ArrowLeft'); + dumpFocus(true, 1, true /* skipObjectCheck */); + + // Select message. + press('ArrowLeft'); + dumpFocus(true, 1, true /* skipObjectCheck */); + + next(); + }, + + async function testExpandingObjectInTrace(next) { + await clearAndLog(`console.log("before");console.warn("warning", obj1);console.log("after");`, 3); + forceSelect(1); + + dumpFocus(true, 1); + press('ArrowRight'); + dumpFocus(true, 1); + + // Expand object. + press('ArrowRight'); + dumpFocus(true, 1); + await ConsoleTestRunner.waitForRemoteObjectsConsoleMessagesPromise(); + press('ArrowDown'); + dumpFocus(true, 1); + press('ArrowDown'); + press('ArrowDown'); + dumpFocus(true, 1); + + press('ArrowUp'); + dumpFocus(true, 1); + press('ArrowUp'); + dumpFocus(true, 1); + + // Collapse trace. + press('ArrowLeft'); + dumpFocus(true, 1); + + // ArrowLeft on message does not collapse object. + press('ArrowLeft'); + dumpFocus(true, 1); + + next(); + }, ]); @@ -66,19 +169,21 @@ eventSender.keyDown(key); } - function dumpFocus() { - const firstMessage = consoleView._visibleViewMessages[0]; + function dumpFocus(activeElement, messageIndex = 0, skipObjectCheck) { + const firstMessage = consoleView._visibleViewMessages[messageIndex]; const hasTrace = !!firstMessage.element().querySelector('.console-message-stack-trace-toggle'); const hasHiddenStackTrace = firstMessage.element().querySelector('.console-message-stack-trace-wrapper > div.hidden'); - const hasCollapsedObject = firstMessage.element().querySelector('.console-view-object-properties-section.hidden'); - const hasExpandedObject = firstMessage.element().querySelector('.console-view-object-properties-section:not(.hidden)'); + const hasCollapsedObject = firstMessage.element().querySelector('.console-view-object-properties-section:not(.expanded)'); + const hasExpandedObject = firstMessage.element().querySelector('.console-view-object-properties-section.expanded'); TestRunner.addResult(`Viewport virtual selection: ${viewport._virtualSelectedIndex}`); - if (hasCollapsedObject) { - TestRunner.addResult(`Has object: collapsed`); - } else if (hasExpandedObject) { - TestRunner.addResult(`Has object: expanded`); + if (!skipObjectCheck) { + if (hasCollapsedObject) { + TestRunner.addResult(`Has object: collapsed`); + } else if (hasExpandedObject) { + TestRunner.addResult(`Has object: expanded`); + } } if (hasTrace) { @@ -88,5 +193,21 @@ const expanded = !firstMessage.collapsed(); TestRunner.addResult(`Is group expanded: ${expanded ? 'YES' : 'NO'}`); } + + if (!activeElement) + return; + var element = document.deepActiveElement(); + if (!element) { + TestRunner.addResult('null'); + return; + } + var name = `activeElement: ${element.tagName}`; + if (element.id) + name += '#' + element.id; + else if (element.className) + name += '.' + element.className.split(' ').join('.'); + if (element.deepTextContent()) + name += '\nactive text: ' + element.deepTextContent(); + TestRunner.addResult(name); } })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/history/history-entry-requires-user-gesture-push-state-expected.txt b/third_party/WebKit/LayoutTests/http/tests/history/history-entry-requires-user-gesture-push-state-expected.txt new file mode 100644 index 0000000..ebea9be --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/history/history-entry-requires-user-gesture-push-state-expected.txt
@@ -0,0 +1,5 @@ + + +============== Back Forward List ============== +curr-> http://127.0.0.1:8000/resources/dummy.html +===============================================
diff --git a/third_party/WebKit/LayoutTests/http/tests/history/history-entry-requires-user-gesture-push-state.html b/third_party/WebKit/LayoutTests/http/tests/history/history-entry-requires-user-gesture-push-state.html new file mode 100644 index 0000000..d5013606 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/history/history-entry-requires-user-gesture-push-state.html
@@ -0,0 +1,17 @@ +<body onload="loaded();"> +<script> +if (window.testRunner) { + testRunner.dumpAsText(); + testRunner.dumpBackForwardList(); + internals.settings.setHistoryEntryRequiresUserGesture(true); +} + +/* Because user gesture required flag is enabled this html file will not be part + * of history + */ +function loaded() { + history.pushState(null, "", "../resources/dummy.html"); +} + +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/all/image-script-upgrade.https.html b/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/all/image-script-upgrade.https.html new file mode 100644 index 0000000..32eb9757 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/all/image-script-upgrade.https.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> +<title>Autoupgrade mixed content: All.</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="http://web-platform.test:8443/mixed-autoupgrade/resources/test.js"></script> + +</head> +<body> + <script> + async_test(t => pass_test(t), "Script autoupgraded"); + async_test(t => assert_image_loads(t), "Image autoupgraded"); + + function assert_image_loads(test) { + var url = new URL("http://web-platform.test:8443/mixed-autoupgrade/resources/pass.png") + var i = document.createElement('img'); + i.onload = test.step_func_done(_ => { + assert_equals(i.naturalHeight, 64, "Height."); + assert_equals(i.naturalWidth, 168, "Width."); + }); + i.onerror = test.unreached_func("Image should load successfully from " + url); + i.src = url; + } +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/blockable/script-upgrade.https.html b/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/blockable/script-upgrade.https.html new file mode 100644 index 0000000..c1011b01 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/blockable/script-upgrade.https.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> +<title>Autoupgrade mixed content: Blockable.</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="http://web-platform.test:8443/mixed-autoupgrade/resources/test.js"></script> + +</head> +<body> + <script> + async_test(t => pass_test(t), "Script autoupgraded"); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/optionally/image-upgrade.https.html b/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/optionally/image-upgrade.https.html new file mode 100644 index 0000000..b39e13b --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/optionally/image-upgrade.https.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> +<head> +<title>Autoupgrade mixed content: Optionally Blockable.</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +</head> +<body> + <script> + async_test(t => assert_image_loads(t), "Image autoupgraded"); + + function assert_image_loads(test) { + var url = new URL("http://web-platform.test:8443/mixed-autoupgrade/resources/pass.png") + var i = document.createElement('img'); + i.onload = test.step_func_done(_ => { + assert_equals(i.naturalHeight, 64, "Height."); + assert_equals(i.naturalWidth, 168, "Width."); + }); + i.onerror = test.unreached_func("Image should load successfully from " + url); + i.src = url; + } +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/resources/pass.png b/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/resources/pass.png new file mode 100644 index 0000000..2fa1e0a --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/resources/pass.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/resources/test.js b/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/resources/test.js new file mode 100644 index 0000000..66db5e78 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/mixed-autoupgrade/resources/test.js
@@ -0,0 +1,3 @@ +function pass_test(test) { + test.done() +}
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-on-play-button.html b/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-on-play-button.html index 989517c..b35fead 100644 --- a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-on-play-button.html +++ b/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-on-play-button.html
@@ -1,13 +1,21 @@ <!DOCTYPE html> <html> -<title>Test that player will play then pause if double tapped on the play button.</title> +<title>Test that player will play then pause if double tapped on the overlay play button.</title> <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../media-controls.js"></script> -<video controls width=400 src="../../content/60_sec_video.webm"></video> +<script src="../overlay-play-button.js"></script> +<body></body> <script> async_test(t => { - const video = document.querySelector('video'); + // This test is only valid when the overlay play button is enabled. + enableOverlayPlayButtonForTest(t); + + const video = document.createElement('video'); + video.controls = true; + video.width = 400; + video.src = '../../content/60_sec_video.webm'; + document.body.appendChild(video); let didPause = false; video.onplaying = t.step_func(() => {
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/immersive-mode-adds-css-class.html b/third_party/WebKit/LayoutTests/media/controls/modern/immersive-mode-adds-css-class.html index b99fe52e..61a49242 100644 --- a/third_party/WebKit/LayoutTests/media/controls/modern/immersive-mode-adds-css-class.html +++ b/third_party/WebKit/LayoutTests/media/controls/modern/immersive-mode-adds-css-class.html
@@ -34,7 +34,6 @@ const buttonPanelStyle = getComputedStyle(buttonPanelElement(video)); const timelineStyle = getComputedStyle(timelineElement(video)); const thumbStyle = getComputedStyle(timelineThumb(video)); - const overlayPlayButtonStyle = getComputedStyle(mediaControlsOverlayPlayButtonInternal(video)); assert_equals('43px', muteButtonStyle.height, 'Mute button height is respected'); assert_equals('24px', fullscreenButtonStyle['background-size'], 'Fullscreen button background size is respected'); @@ -45,7 +44,12 @@ assert_equals('5px', timelineStyle.height, 'Timeline height is respected'); assert_equals('471px', timelineStyle['max-width'], 'Timeline max-width is respected'); assert_equals('16px', thumbStyle.width, 'Thumb width is respected'); - assert_equals('64px', overlayPlayButtonStyle.height, 'Overlay play button height is respected'); + + if (internals.runtimeFlags.mediaControlsOverlayPlayButtonEnabled) { + const overlayPlayButtonStyle = getComputedStyle(mediaControlsOverlayPlayButtonInternal(video)); + assert_equals('64px', overlayPlayButtonStyle.height, 'Overlay play button height is respected'); + } + } }); </script>
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/overlay-play-button-tap-to-hide.html b/third_party/WebKit/LayoutTests/media/controls/modern/overlay-play-button-tap-to-hide.html index f9191ad..729fcc0 100644 --- a/third_party/WebKit/LayoutTests/media/controls/modern/overlay-play-button-tap-to-hide.html +++ b/third_party/WebKit/LayoutTests/media/controls/modern/overlay-play-button-tap-to-hide.html
@@ -3,11 +3,18 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../media-controls.js"></script> +<script src="../overlay-play-button.js"></script> <body> -<video id=video width=400 controls preload=metadata></video> <script> async_test((t) => { - const video = document.getElementById('video'); + // This test is only valid when the overlay play button is enabled. + enableOverlayPlayButtonForTest(t); + + const video = document.createElement('video'); + video.width = 400; + video.controls = true; + video.preload = 'metadata' + document.body.appendChild(video); const button = mediaControlsOverlayPlayButtonInternal(video); const controls = mediaControls(video); const overlay = mediaControlsOverlayPlayButton(video);
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-outside.html b/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-outside.html index ae07b7e5..f253040 100644 --- a/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-outside.html +++ b/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-outside.html
@@ -4,10 +4,18 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../media-controls.js"></script> -<video controls width=400 src="../../content/60_sec_video.webm"></video> +<script src="../overlay-play-button.js"></script> +<body></body> <script> async_test(t => { - const video = document.querySelector('video'); + // This test is only valid when the overlay play button is enabled. + enableOverlayPlayButtonForTest(t); + + const video = document.createElement('video'); + video.controls = true; + video.width = 400; + video.src = '../../content/60_sec_video.webm'; + document.body.appendChild(video); video.addEventListener('playing', t.step_func(() => { // Single tap in the top right hand corner @@ -16,15 +24,10 @@ singleTapAtCoordinates(coordinates[0] + 1, coordinates[1] + 1); }), { once: true }); - video.addEventListener('pause', t.unreached_func()); + video.addEventListener('pause', t.done.bind(t)); video.addEventListener('webkitfullscreenchange', t.unreached_func()); - video.ontimeupdate = t.step_func(() => { - if (video.currentTime > 0) - t.done(); - }); - video.play(); }); </script>
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-overlay-closes-overflow-menu.html b/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-overlay-closes-overflow-menu.html index bfcb67d..0948e16 100644 --- a/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-overlay-closes-overflow-menu.html +++ b/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-overlay-closes-overflow-menu.html
@@ -4,10 +4,19 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../media-controls.js"></script> -<video controls width=400 src="../../content/60_sec_video.webm"></video> +<script src="../overlay-play-button.js"></script> +<body></body> <script> async_test(t => { - const video = document.querySelector('video'); + // This test is only valid when the overlay play button is enabled. + enableOverlayPlayButtonForTest(t); + + const video = document.createElement('video'); + video.controls = true; + video.width = 400; + video.src='../../content/60_sec_video.webm'; + document.body.appendChild(video); + var button = overflowButton(video); var menu = overflowMenu(video); // Need to add a text track for the overflow menu to appear.
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-play-button.html b/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-play-button.html index e7460298..b91556b 100644 --- a/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-play-button.html +++ b/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-play-button.html
@@ -4,10 +4,18 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../media-controls.js"></script> -<video controls width=400 src="../../content/60_sec_video.webm"></video> +<script src="../overlay-play-button.js"></script> +<body></body> <script> async_test(t => { - const video = document.querySelector('video'); + // This test is only valid when the overlay play button is enabled. + enableOverlayPlayButtonForTest(t); + + const video = document.createElement('video'); + video.controls = true; + video.width = 400; + video.src='../../content/60_sec_video.webm'; + document.body.appendChild(video); video.addEventListener('playing', t.step_func(() => { // Single tap in the middle of the button.
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/singletouch-on-play-button.html b/third_party/WebKit/LayoutTests/media/controls/modern/singletouch-on-play-button.html index fb1c5de..860c963 100644 --- a/third_party/WebKit/LayoutTests/media/controls/modern/singletouch-on-play-button.html +++ b/third_party/WebKit/LayoutTests/media/controls/modern/singletouch-on-play-button.html
@@ -4,10 +4,18 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../media-controls.js"></script> -<video controls width=400 src="../../content/60_sec_video.webm"></video> +<script src="../overlay-play-button.js"></script> +<body></body> <script> async_test(t => { - const video = document.querySelector('video'); + // This test is only valid when the overlay play button is enabled. + enableOverlayPlayButtonForTest(t); + + const video = document.createElement('video'); + video.controls = true; + video.width = 400; + video.src='../../content/60_sec_video.webm'; + document.body.appendChild(video); video.addEventListener('playing', t.step_func(() => { // Single tap in the middle of the button.
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/video-does-not-go-fullscreen-on-double-click-before-preload.html b/third_party/WebKit/LayoutTests/media/controls/modern/video-does-not-go-fullscreen-on-double-click-before-preload.html index f8595bd1..34bb9fb 100644 --- a/third_party/WebKit/LayoutTests/media/controls/modern/video-does-not-go-fullscreen-on-double-click-before-preload.html +++ b/third_party/WebKit/LayoutTests/media/controls/modern/video-does-not-go-fullscreen-on-double-click-before-preload.html
@@ -4,10 +4,18 @@ <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> <script src="../../media-controls.js"></script> -<video controls width=400 preload=none src="../../content/60_sec_video.webm"></video> +<script src="../overlay-play-button.js"></script> +<body></body> <script> async_test(t => { - const video = document.querySelector('video'); + // This test is only valid when the overlay play button is enabled. + enableOverlayPlayButtonForTest(t); + + const video = document.createElement('video'); + video.controls = true; + video.width = 400; + video.src='../../content/60_sec_video.webm'; + document.body.appendChild(video); video.addEventListener("webkitfullscreenchange", t.unreached_func()); window.onload = t.step_func(() => {
diff --git a/third_party/WebKit/LayoutTests/media/controls/overlay-play-button-resizes-with-video.html b/third_party/WebKit/LayoutTests/media/controls/overlay-play-button-resizes-with-video.html index cfb8e57..2bcbd11 100644 --- a/third_party/WebKit/LayoutTests/media/controls/overlay-play-button-resizes-with-video.html +++ b/third_party/WebKit/LayoutTests/media/controls/overlay-play-button-resizes-with-video.html
@@ -4,6 +4,7 @@ <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> <script src="../media-controls.js"></script> +<script src="overlay-play-button.js"></script> <body></body> <script> const testCases = [ @@ -23,6 +24,9 @@ }); function runTestCase(t) { + // This test is only valid when the overlay play button is enabled. + enableOverlayPlayButtonForTest(t); + let test = t.properties; test.video = createVideo(test); setTimeout(t.step_func_done(() => {
diff --git a/third_party/WebKit/LayoutTests/media/controls/tap-on-overlay-play-button-cant-be-preempted.html b/third_party/WebKit/LayoutTests/media/controls/tap-on-overlay-play-button-cant-be-preempted.html index 62da232..a48b0a5 100644 --- a/third_party/WebKit/LayoutTests/media/controls/tap-on-overlay-play-button-cant-be-preempted.html +++ b/third_party/WebKit/LayoutTests/media/controls/tap-on-overlay-play-button-cant-be-preempted.html
@@ -4,13 +4,21 @@ <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> <script src="../media-controls.js"></script> +<script src="overlay-play-button.js"></script> <div id="outer"> -<video controls width=500 preload=none src="../content/60_sec_video.webm"></video> </div> <script> async_test(t => { - const video = document.querySelector('video'); + // This test is only valid when the overlay play button is enabled. + enableOverlayPlayButtonForTest(t); + const outerDiv = document.getElementById('outer'); + const video = document.createElement('video'); + video.controls = true; + video.width = 500; + video.preload = 'none'; + video.src = '../content/60_sec_video.webm'; + outerDiv.appendChild(video); video.addEventListener('loadedmetadata', t.step_func(() => { singleTouchOnControl(mediaControlsOverlayPlayButton(video));
diff --git a/third_party/WebKit/LayoutTests/media/controls/video-enter-exit-fullscreen-while-hovering-shows-controls.html b/third_party/WebKit/LayoutTests/media/controls/video-enter-exit-fullscreen-while-hovering-shows-controls.html index 100f4af5..b1d82643 100644 --- a/third_party/WebKit/LayoutTests/media/controls/video-enter-exit-fullscreen-while-hovering-shows-controls.html +++ b/third_party/WebKit/LayoutTests/media/controls/video-enter-exit-fullscreen-while-hovering-shows-controls.html
@@ -19,7 +19,7 @@ var panel = mediaControlsButton(video, "panel"); // Move mouse to the play button and start playing the video. - clickAtCoordinates(...mediaControlsButtonCoordinates(video, "overlay-play-button")); + clickAtCoordinates(...elementCoordinates(enabledPlayButton(video))); assert_equals(getComputedStyle(panel).opacity, "1", "Inline controls should initially show since controls " +
diff --git a/third_party/WebKit/LayoutTests/media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html b/third_party/WebKit/LayoutTests/media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html index ed356bb..1c434cf8 100644 --- a/third_party/WebKit/LayoutTests/media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html +++ b/third_party/WebKit/LayoutTests/media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html
@@ -20,7 +20,7 @@ var panel = mediaControlsButton(video, "panel"); // Move mouse to the play button and start playing the video. - clickAtCoordinates(...mediaControlsButtonCoordinates(video, "overlay-play-button")); + clickAtCoordinates(...elementCoordinates(enabledPlayButton(video))); assert_equals(getComputedStyle(panel).opacity, "1", "Inline controls should initially show since controls " +
diff --git a/third_party/WebKit/LayoutTests/media/media-controls-tap-show-controls-without-activating.html b/third_party/WebKit/LayoutTests/media/media-controls-tap-show-controls-without-activating.html index fd3bc4d..3cb54aa 100644 --- a/third_party/WebKit/LayoutTests/media/media-controls-tap-show-controls-without-activating.html +++ b/third_party/WebKit/LayoutTests/media/media-controls-tap-show-controls-without-activating.html
@@ -14,7 +14,7 @@ runAfterHideMediaControlsTimerFired(t.step_func(function() { assert_false(isControlsPanelVisible(video)); - var coords = mediaControlsButtonCoordinates(video, "overlay-play-button"); + var coords = elementCoordinates(enabledPlayButton(video)); eventSender.gestureTapDown(coords[0], coords[1]); assert_false(video.paused);
diff --git a/third_party/WebKit/LayoutTests/media/media-controls.js b/third_party/WebKit/LayoutTests/media/media-controls.js index 083af60..d0504e93 100644 --- a/third_party/WebKit/LayoutTests/media/media-controls.js +++ b/third_party/WebKit/LayoutTests/media/media-controls.js
@@ -287,6 +287,13 @@ return mediaControlsButton(videoElement, 'play-button'); } +function enabledPlayButton(videoElement) { + if (internals.runtimeFlags.mediaControlsOverlayPlayButtonEnabled) { + return mediaControlsOverlayPlayButton(videoElement); + } + return playButton(videoElement); +} + function muteButton(videoElement) { return mediaControlsButton(videoElement, 'mute-button'); }
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-always-visible-when-control-hovered.html b/third_party/WebKit/LayoutTests/media/video-controls-always-visible-when-control-hovered.html index dded11d1..0eb24f737 100644 --- a/third_party/WebKit/LayoutTests/media/video-controls-always-visible-when-control-hovered.html +++ b/third_party/WebKit/LayoutTests/media/video-controls-always-visible-when-control-hovered.html
@@ -13,7 +13,7 @@ assert_true(video.paused); // Click the play button. - var playCoords = mediaControlsButtonCoordinates(video, "overlay-play-button"); + var playCoords = elementCoordinates(enabledPlayButton(video)); eventSender.mouseMoveTo(playCoords[0], playCoords[1]); eventSender.mouseDown(); eventSender.mouseUp();
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-auto-hide-after-play-by-touch.html b/third_party/WebKit/LayoutTests/media/video-controls-auto-hide-after-play-by-touch.html index 9760781..4650405 100644 --- a/third_party/WebKit/LayoutTests/media/video-controls-auto-hide-after-play-by-touch.html +++ b/third_party/WebKit/LayoutTests/media/video-controls-auto-hide-after-play-by-touch.html
@@ -14,7 +14,7 @@ assert_true(video.paused); // Click the play button. - var playCoords = mediaControlsButtonCoordinates(video, "overlay-play-button"); + var playCoords = elementCoordinates(enabledPlayButton(video)); var clickX = playCoords[0]; var clickY = playCoords[1]; eventSender.gestureTap(clickX, clickY);
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-hide-after-touch-on-control.html b/third_party/WebKit/LayoutTests/media/video-controls-hide-after-touch-on-control.html index a838e2e..5809fa9 100644 --- a/third_party/WebKit/LayoutTests/media/video-controls-hide-after-touch-on-control.html +++ b/third_party/WebKit/LayoutTests/media/video-controls-hide-after-touch-on-control.html
@@ -12,7 +12,7 @@ assert_true(video.paused); // Tap the play button - var coords = mediaControlsButtonCoordinates(video, "overlay-play-button"); + var coords = elementCoordinates(enabledPlayButton(video)); eventSender.gestureTapDown(coords[0], coords[1]); eventSender.gestureShowPress(coords[0], coords[1]); eventSender.gestureTap(coords[0], coords[1]);
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-hide-on-move-outside-controls.html b/third_party/WebKit/LayoutTests/media/video-controls-hide-on-move-outside-controls.html index fecb0dd2..8e3c19c 100644 --- a/third_party/WebKit/LayoutTests/media/video-controls-hide-on-move-outside-controls.html +++ b/third_party/WebKit/LayoutTests/media/video-controls-hide-on-move-outside-controls.html
@@ -12,7 +12,7 @@ assert_true(video.paused); // Click the play button. - var coords = mediaControlsButtonCoordinates(video, "overlay-play-button"); + var coords = elementCoordinates(enabledPlayButton(video)); eventSender.mouseMoveTo(coords[0], coords[1]); eventSender.mouseDown(); eventSender.mouseUp();
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-transformed.html b/third_party/WebKit/LayoutTests/media/video-controls-transformed.html index 4b4d86fa..1ee7be9 100644 --- a/third_party/WebKit/LayoutTests/media/video-controls-transformed.html +++ b/third_party/WebKit/LayoutTests/media/video-controls-transformed.html
@@ -17,7 +17,7 @@ video.oncanplaythrough = t.step_func_done(function() { // Find the play button and click the middle of its bounding box. - var playCoords = mediaControlsButtonCoordinates(video, "overlay-play-button"); + var playCoords = elementCoordinates(enabledPlayButton(video)); eventSender.mouseMoveTo(playCoords[0], playCoords[1]); eventSender.mouseDown(); eventSender.mouseUp();
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-visibility-multimodal-mouse-after-touch.html b/third_party/WebKit/LayoutTests/media/video-controls-visibility-multimodal-mouse-after-touch.html index 97ac8e4..55c83be 100644 --- a/third_party/WebKit/LayoutTests/media/video-controls-visibility-multimodal-mouse-after-touch.html +++ b/third_party/WebKit/LayoutTests/media/video-controls-visibility-multimodal-mouse-after-touch.html
@@ -12,7 +12,7 @@ assert_true(video.paused); // Tap (touch input) the play button. - var coords = mediaControlsButtonCoordinates(video, "overlay-play-button"); + var coords = elementCoordinates(enabledPlayButton(video)); eventSender.gestureTapDown(coords[0], coords[1]); eventSender.gestureShowPress(coords[0], coords[1]); eventSender.gestureTap(coords[0], coords[1]);
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-visibility-multimodal-touch-after-mouse.html b/third_party/WebKit/LayoutTests/media/video-controls-visibility-multimodal-touch-after-mouse.html index f389cd0..6fe2561 100644 --- a/third_party/WebKit/LayoutTests/media/video-controls-visibility-multimodal-touch-after-mouse.html +++ b/third_party/WebKit/LayoutTests/media/video-controls-visibility-multimodal-touch-after-mouse.html
@@ -7,12 +7,13 @@ <script> async_test(function(t) { var video = document.querySelector("video"); + enableTestMode(video); video.oncanplaythrough = t.step_func(function() { assert_true(video.paused); // Hover the control with the mouse. - var coords = mediaControlsButtonCoordinates(video, "overlay-play-button"); + var coords = elementCoordinates(enabledPlayButton(video)); eventSender.mouseMoveTo(coords[0], coords[1]); // And then tap (touch input) the play button.
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-zoomed.html b/third_party/WebKit/LayoutTests/media/video-controls-zoomed.html index 07f985b..04b9cc1 100644 --- a/third_party/WebKit/LayoutTests/media/video-controls-zoomed.html +++ b/third_party/WebKit/LayoutTests/media/video-controls-zoomed.html
@@ -22,7 +22,7 @@ }); // Find the play button and click the middle of its bounding box. - var playCoords = mediaControlsButtonCoordinates(video, "overlay-play-button"); + var playCoords = elementCoordinates(enabledPlayButton(video)); eventSender.mouseMoveTo(playCoords[0] * 1.5, playCoords[1] * 1.5); eventSender.mouseDown();
diff --git a/third_party/WebKit/LayoutTests/media/video-play-require-user-gesture.html b/third_party/WebKit/LayoutTests/media/video-play-require-user-gesture.html index 136274c6..2667aef 100644 --- a/third_party/WebKit/LayoutTests/media/video-play-require-user-gesture.html +++ b/third_party/WebKit/LayoutTests/media/video-play-require-user-gesture.html
@@ -19,7 +19,7 @@ // User gesture initiated. userGestureInitiated = true; - var playCoords = mediaControlsButtonCoordinates(video, "overlay-play-button"); + var playCoords = elementCoordinates(enabledPlayButton(video)); eventSender.mouseMoveTo(playCoords[0], playCoords[1]); eventSender.mouseDown(); eventSender.mouseUp();
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/video-paint-invalidation-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/video-paint-invalidation-expected.txt index a0c1265..e2b1cf40 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/video-paint-invalidation-expected.txt +++ b/third_party/WebKit/LayoutTests/paint/invalidation/video-paint-invalidation-expected.txt
@@ -36,22 +36,6 @@ "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV)", "position": [8, 8], "bounds": [320, 240] - }, - { - "name": "LayoutFlexibleBox DIV", - "position": [8, 8], - "bounds": [320, 240] - }, - { - "name": "Child Containment Layer", - "position": [8, 8], - "bounds": [320, 240], - "drawsContent": false - }, - { - "name": "LayoutButton (positioned) INPUT", - "position": [118, 66], - "bounds": [100, 100] } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-controls-layer-creation-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-controls-layer-creation-expected.png index b6aaaf4..4f5be9b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-controls-layer-creation-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-controls-layer-creation-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/overflow-of-video-outline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/overflow-of-video-outline-expected.png index dd431b4..8d98b38 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/overflow-of-video-outline-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/overflow-of-video-outline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls-after-reload-expected.png index 44d9038..af2d071b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-after-reload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-after-reload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-after-reload-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls-after-reload-expected.txt index 07d397e..2195cd9 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-after-reload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-after-reload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,212) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png index 3af4d8b..8307e65 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls-strict-expected.png index f4562b3..58856e2 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls-strict-expected.txt index 14b3278f..32e696c 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-strict-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,220) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-expected.png index 89a5a0e..ae1db3b4 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-expected.txt index 5d39a85..a46b3d6 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (18,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (128,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (18,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 66x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 66x16 - text run at (0,14) width 66: "/ 0:06" - LayoutBlockFlow {DIV} at (114,48) size 110x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 66x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 66x16 + text run at (0,16) width 66: "/ 0:06" + LayoutBlockFlow {DIV} at (146,48) size 78x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (242,212) size 0x48 transparent @@ -68,19 +65,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,284) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,342) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,452) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,452) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-strict-expected.png index 353a2ce8..2948071 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-strict-expected.txt index 22b3e5e6..f039fd4 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-styling-strict-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,220) size 0x48 transparent @@ -68,19 +65,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (332,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (442,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (332,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (556,220) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls-without-preload-expected.png index d8fd7cb..0f254c8 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-without-preload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-without-preload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-without-preload-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls-without-preload-expected.txt index 119340a..1ece823 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-without-preload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-without-preload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,212) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/lazy-loaded-style-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls/lazy-loaded-style-expected.txt index 9c7d82f..a005ba0 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls/lazy-loaded-style-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/lazy-loaded-style-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x300 layer at (8,8) size 400x300 LayoutFlexibleBox {DIV} at (0,0) size 400x300 -layer at (151,89) size 115x115 - LayoutButton (positioned) {INPUT} at (142.50,80.50) size 115x115 - LayoutBlockFlow (anonymous) at (20,20) size 75x75 - LayoutBlockFlow {DIV} at (0,0) size 75x75 [bgcolor=#FFFFFFE6] layer at (8,236) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,228) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 220x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 188x0 LayoutButton {INPUT} at (304,0) size 48x48 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,236) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png index 7744a07..120b231 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt index 362a1479..5bac4a4b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x327.27 layer at (8,8) size 400x327 LayoutFlexibleBox {DIV} at (0,0) size 400x327.27 -layer at (147,99) size 122x122 - LayoutButton (positioned) {INPUT} at (139.13,90.75) size 121.75x121.75 - LayoutBlockFlow (anonymous) at (20,20) size 81.75x81.75 - LayoutBlockFlow {DIV} at (0,0) size 81.75x81.75 [bgcolor=#FFFFFFE6] layer at (8,263) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,255.27) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (84,48) size 220x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (116,48) size 188x0 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,263) size 48x48 transparent LayoutButton {INPUT} at (304,0) size 48x48 [color=#808080]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.png index 7744a07..4341c83 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.txt index 362a1479..5bac4a4b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/paint-controls-webkit-appearance-none-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x327.27 layer at (8,8) size 400x327 LayoutFlexibleBox {DIV} at (0,0) size 400x327.27 -layer at (147,99) size 122x122 - LayoutButton (positioned) {INPUT} at (139.13,90.75) size 121.75x121.75 - LayoutBlockFlow (anonymous) at (20,20) size 81.75x81.75 - LayoutBlockFlow {DIV} at (0,0) size 81.75x81.75 [bgcolor=#FFFFFFE6] layer at (8,263) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,255.27) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (84,48) size 220x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (116,48) size 188x0 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,263) size 48x48 transparent LayoutButton {INPUT} at (304,0) size 48x48 [color=#808080]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png index 3aaa55c..78014c8 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt index a6e883e..c2c340d 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -22,19 +22,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -70,19 +67,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,297) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,355) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,465) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -120,19 +114,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,542) size 320x240 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,600) size 100x100 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,710) size 320x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png index 1887e224..138bbbf50 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.txt index 3e0bffd1..0e9e2c0 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.txt
@@ -42,13 +42,12 @@ LayoutFlexibleBox {DIV} at (0,0) size 300x54 [bgcolor=#F1F3F4] layer at (308,104) size 300x54 scrollHeight 55 LayoutFlexibleBox {DIV} at (0,0) size 300x54 - LayoutSlider {INPUT} at (10,-1) size 248x56 [color=#9D968E] - LayoutFlexibleBox {DIV} at (16,26) size 216x4 - LayoutButton {INPUT} at (258,11) size 32x32 -layer at (334,129) size 216x4 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 216x4 [bgcolor=#00000033] -layer at (334,129) size 216x4 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 216x4 + LayoutSlider {INPUT} at (10,-1) size 280x56 [color=#9D968E] + LayoutFlexibleBox {DIV} at (16,26) size 248x4 +layer at (334,129) size 248x4 + LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 248x4 [bgcolor=#00000033] +layer at (334,129) size 248x4 + LayoutBlockFlow (positioned) {DIV} at (0,0) size 248x4 layer at (334,129) size 0x4 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x4 [bgcolor=#000000DE] layer at (334,129) size 0x4 @@ -82,13 +81,12 @@ LayoutFlexibleBox {DIV} at (0,0) size 300x54 [bgcolor=#F1F3F4] layer at (308,259) size 300x54 scrollHeight 55 LayoutFlexibleBox {DIV} at (0,0) size 300x54 - LayoutSlider {INPUT} at (10,-1) size 248x56 [color=#9D968E] - LayoutFlexibleBox {DIV} at (16,26) size 216x4 - LayoutButton {INPUT} at (258,11) size 32x32 -layer at (334,284) size 216x4 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 216x4 [bgcolor=#00000033] -layer at (334,284) size 216x4 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 216x4 + LayoutSlider {INPUT} at (10,-1) size 280x56 [color=#9D968E] + LayoutFlexibleBox {DIV} at (16,26) size 248x4 +layer at (334,284) size 248x4 + LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 248x4 [bgcolor=#00000033] +layer at (334,284) size 248x4 + LayoutBlockFlow (positioned) {DIV} at (0,0) size 248x4 layer at (334,284) size 0x4 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x4 [bgcolor=#000000DE] layer at (334,284) size 0x4
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-grey-scrubber-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-grey-scrubber-expected.png index 3b15efd..a9868aa 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-grey-scrubber-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-grey-scrubber-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-grey-scrubber-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-grey-scrubber-expected.txt index 250c2ab..0f8ed2e3 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-grey-scrubber-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-grey-scrubber-expected.txt
@@ -13,16 +13,13 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 300x150 layer at (8,8) size 300x150 LayoutFlexibleBox {DIV} at (0,0) size 300x150 -layer at (114,27) size 88x88 - LayoutButton (positioned) {INPUT} at (106,19) size 88x88 - LayoutBlockFlow (anonymous) at (20,20) size 48x48 - LayoutBlockFlow {DIV} at (0,0) size 48x48 [bgcolor=#FFFFFFE6] layer at (8,86) size 300x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,78) size 300x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (44,48) size 160x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (76,48) size 128x0 layer at (212,86) size 48x48 transparent LayoutButton {INPUT} at (204,0) size 48x48 [color=#808080] layer at (260,86) size 48x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-controls-rendering-expected.png index d186f610..6f061986 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-controls-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/video-controls-rendering-expected.txt index 63195ebd..49823c2 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-controls-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-controls-rendering-expected.txt
@@ -22,19 +22,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,212) size 0x48 transparent @@ -69,19 +66,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,284) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,342) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,452) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,452) size 0x48 transparent @@ -118,19 +112,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,524) size 320x240 backgroundClip at (8,524) size 320x76 clip at (8,524) size 320x76 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,582) size 100x100 backgroundClip at (118,582) size 100x18 clip at (118,582) size 100x18 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,692) size 320x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,692) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-display-toggle-expected.png index 32c2e159..3368e343 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-display-toggle-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-display-toggle-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-display-toggle-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/video-display-toggle-expected.txt index 1e6ca8e..fd4da0c 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-display-toggle-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-display-toggle-expected.txt
@@ -16,19 +16,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,28) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,86) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,196) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,196) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-empty-source-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-empty-source-expected.png index 12d0f5f..8e2e3c1 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-empty-source-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-empty-source-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-empty-source-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/video-empty-source-expected.txt index 0da22bb..1b9541c5 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-empty-source-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-empty-source-expected.txt
@@ -17,17 +17,14 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 300x150 layer at (9,45) size 300x150 LayoutFlexibleBox {DIV} at (0,0) size 300x150 -layer at (115,64) size 88x88 - LayoutButton (positioned) {INPUT} at (106,19) size 88x88 - LayoutBlockFlow (anonymous) at (20,20) size 48x48 -layer at (135,84) size 48x48 transparent - LayoutBlockFlow {DIV} at (0,0) size 48x48 [bgcolor=#FFFFFFE6] layer at (9,123) size 300x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,78) size 300x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (44,48) size 112x0 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (76,48) size 80x0 +layer at (9,123) size 48x48 transparent + LayoutButton {INPUT} at (0,0) size 48x48 [color=#808080] layer at (165,123) size 48x48 transparent LayoutButton {INPUT} at (156,0) size 48x48 [color=#808080] layer at (213,123) size 48x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-no-audio-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-no-audio-expected.png index 1d95d1b..3072ab0b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-no-audio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-no-audio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-no-audio-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/video-no-audio-expected.txt index d067b18..6601fee6 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-no-audio-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-no-audio-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 352x288 layer at (8,44) size 352x288 LayoutFlexibleBox {DIV} at (0,0) size 352x288 -layer at (128,120) size 112x112 - LayoutButton (positioned) {INPUT} at (120,76) size 112x112 - LayoutBlockFlow (anonymous) at (20,20) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] layer at (8,260) size 352x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,216) size 352x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (84,48) size 172x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (116,48) size 140x0 LayoutButton {INPUT} at (304,0) size 48x48 layer at (264,260) size 48x48 transparent LayoutButton {INPUT} at (256,0) size 48x48 [color=#808080]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png index f4b0048..0d30c06 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.txt index b75f1d0..be34eb7f 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.txt
@@ -15,33 +15,22 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 layer at (57,85) size 240x180 LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (111,91) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (57,157) size 240x72 scrollWidth 258 +layer at (57,157) size 240x72 LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 42x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x24 - text run at (0,21) width 42: "0:00" - LayoutBlockFlow {DIV} at (72,-60) size 42x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 42: "0:06" - LayoutBlockFlow {DIV} at (114,72) size 0x0 - LayoutButton {INPUT} at (114,0) size 72x72 - LayoutButton {INPUT} at (186,0) size 72x72 -layer at (171,157) size 0x72 transparent - LayoutSlider {INPUT} at (114,0) size 0x72 [color=#9D968E] + LayoutButton {INPUT} at (0,0) size 72x72 + LayoutBlockFlow {DIV} at (72,72) size 96x0 + LayoutButton {INPUT} at (168,0) size 72x72 +layer at (225,157) size 0x72 transparent + LayoutSlider {INPUT} at (168,0) size 0x72 [color=#9D968E] LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (171,190) size 18x6 +layer at (225,190) size 18x6 LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (171,190) size 18x6 scrollWidth 27 +layer at (225,190) size 18x6 scrollWidth 27 LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (171,190) size 0x6 +layer at (225,190) size 0x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (171,190) size 27x6 backgroundClip at (171,190) size 18x6 clip at (171,190) size 18x6 +layer at (225,190) size 27x6 backgroundClip at (225,190) size 18x6 clip at (225,190) size 18x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] layer at (57,229) size 240x36 LayoutSlider {INPUT} at (0,144) size 240x36 [color=#9D968E] @@ -65,33 +54,22 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 layer at (43,291) size 268x218 clip at (43,291) size 240x180 LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (104,306) size 153x153 clip at (104,306) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (49,361) size 249x113 clip at (49,361) size 240x72 scrollWidth 258 +layer at (49,361) size 249x113 clip at (49,361) size 240x72 LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 42x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x24 - text run at (0,21) width 42: "0:00" - LayoutBlockFlow {DIV} at (72,-60) size 42x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 42: "0:06" - LayoutBlockFlow {DIV} at (114,72) size 0x0 - LayoutButton {INPUT} at (114,0) size 72x72 - LayoutButton {INPUT} at (186,0) size 72x72 -layer at (162,381) size 12x71 transparent - LayoutSlider {INPUT} at (114,0) size 0x72 [color=#9D968E] + LayoutButton {INPUT} at (0,0) size 72x72 + LayoutBlockFlow {DIV} at (72,72) size 96x0 + LayoutButton {INPUT} at (168,0) size 72x72 +layer at (215,391) size 12x71 transparent + LayoutSlider {INPUT} at (168,0) size 0x72 [color=#9D968E] LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (167,414) size 19x9 +layer at (221,423) size 18x9 LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (167,414) size 19x9 clip at (167,414) size 18x6 scrollWidth 27 +layer at (221,423) size 18x9 clip at (221,423) size 18x6 scrollWidth 27 LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (167,414) size 2x6 +layer at (221,423) size 1x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (167,414) size 28x10 backgroundClip at (167,414) size 19x9 clip at (167,414) size 19x9 +layer at (221,423) size 27x11 backgroundClip at (221,423) size 18x9 clip at (221,423) size 18x9 LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] layer at (43,432) size 243x77 LayoutSlider {INPUT} at (0,144) size 240x36 [color=#9D968E]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png index ca51ff90..8aedabea 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png index e16ffc5..ef81892 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-overlay-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-overlay-scroll-expected.txt deleted file mode 100644 index c018a97..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-overlay-scroll-expected.txt +++ /dev/null
@@ -1,50 +0,0 @@ -EVENT(fullscreenchange) -END OF TEST -{ - "layers": [ - { - "name": "LayoutVideo (positioned) VIDEO id='video'", - "bounds": [800, 600], - "drawsContent": false - }, - { - "name": "LayoutFlexibleBox (relative positioned) DIV class='phase-pre-ready state-no-source use-default-poster sizing-medium'", - "bounds": [800, 600], - "contentsOpaque": true, - "backgroundColor": "#333333" - }, - { - "name": "LayoutBlockFlow (positioned) DIV", - "bounds": [800, 600], - "drawsContent": false - }, - { - "name": "LayoutFlexibleBox DIV", - "bounds": [800, 600] - }, - { - "name": "Child Containment Layer", - "bounds": [800, 600], - "drawsContent": false - }, - { - "name": "LayoutButton (positioned) INPUT", - "position": [335, 223], - "bounds": [130, 130] - }, - { - "name": "Ancestor Clipping Layer", - "position": [335, 223], - "bounds": [130, 130], - "drawsContent": false - }, - { - "name": "LayoutBlockFlow DIV", - "position": [336, 224], - "bounds": [128, 128], - "opacity": 0.300000011920929, - "backgroundColor": "#FFFFFFE6" - } - ] -} -
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png index ca51ff90..8aedabea 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/lazy-loaded-style-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/lazy-loaded-style-expected.txt index 9c7d82f..a005ba0 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/lazy-loaded-style-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/lazy-loaded-style-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x300 layer at (8,8) size 400x300 LayoutFlexibleBox {DIV} at (0,0) size 400x300 -layer at (151,89) size 115x115 - LayoutButton (positioned) {INPUT} at (142.50,80.50) size 115x115 - LayoutBlockFlow (anonymous) at (20,20) size 75x75 - LayoutBlockFlow {DIV} at (0,0) size 75x75 [bgcolor=#FFFFFFE6] layer at (8,236) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,228) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 220x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 188x0 LayoutButton {INPUT} at (304,0) size 48x48 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,236) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png index 7744a07..120b231 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt index 362a1479..5bac4a4b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x327.27 layer at (8,8) size 400x327 LayoutFlexibleBox {DIV} at (0,0) size 400x327.27 -layer at (147,99) size 122x122 - LayoutButton (positioned) {INPUT} at (139.13,90.75) size 121.75x121.75 - LayoutBlockFlow (anonymous) at (20,20) size 81.75x81.75 - LayoutBlockFlow {DIV} at (0,0) size 81.75x81.75 [bgcolor=#FFFFFFE6] layer at (8,263) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,255.27) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (84,48) size 220x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (116,48) size 188x0 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,263) size 48x48 transparent LayoutButton {INPUT} at (304,0) size 48x48 [color=#808080]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.png index 7744a07..4341c83 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.txt index 362a1479..5bac4a4b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x327.27 layer at (8,8) size 400x327 LayoutFlexibleBox {DIV} at (0,0) size 400x327.27 -layer at (147,99) size 122x122 - LayoutButton (positioned) {INPUT} at (139.13,90.75) size 121.75x121.75 - LayoutBlockFlow (anonymous) at (20,20) size 81.75x81.75 - LayoutBlockFlow {DIV} at (0,0) size 81.75x81.75 [bgcolor=#FFFFFFE6] layer at (8,263) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,255.27) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (84,48) size 220x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (116,48) size 188x0 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,263) size 48x48 transparent LayoutButton {INPUT} at (304,0) size 48x48 [color=#808080]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png index 3aaa55c..78014c8 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt index a6e883e..c2c340d 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -22,19 +22,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -70,19 +67,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,297) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,355) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,465) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -120,19 +114,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,542) size 320x240 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,600) size 100x100 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,710) size 320x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.png index 4c6ac2f..8c2df1c 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.txt index b61bba8e..5a9b399 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-after-reload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png index 3af4d8b..8307e65 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.png index 4e3bc5b..45b8be89 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.txt index 71f1589..8147bf17 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-strict-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.png index 05df64de..744888a 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.txt index 4006d6d..54b6ba8 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (18,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (128,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (18,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 66x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 66x16 - text run at (0,14) width 66: "/ 0:06" - LayoutBlockFlow {DIV} at (114,48) size 62x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 66x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 66x16 + text run at (0,16) width 66: "/ 0:06" + LayoutBlockFlow {DIV} at (146,48) size 30x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -69,19 +66,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,284) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,342) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,452) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.png index 28f4432..e4574ee 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.txt index 87f4643..2dbdf17 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-styling-strict-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -69,19 +66,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (332,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (442,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (332,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.png index d1b1798d..43d1d77 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.txt index 73d2da6..fbe4340 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-without-preload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.png index 3aaa55c..78014c8 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.txt index a6e883e..c2c340d 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -22,19 +22,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -70,19 +67,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,297) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,355) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,465) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -120,19 +114,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,542) size 320x240 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,600) size 100x100 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,710) size 320x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png index 1887e224..138bbbf50 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.txt index 3e0bffd1..0e9e2c0 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.txt
@@ -42,13 +42,12 @@ LayoutFlexibleBox {DIV} at (0,0) size 300x54 [bgcolor=#F1F3F4] layer at (308,104) size 300x54 scrollHeight 55 LayoutFlexibleBox {DIV} at (0,0) size 300x54 - LayoutSlider {INPUT} at (10,-1) size 248x56 [color=#9D968E] - LayoutFlexibleBox {DIV} at (16,26) size 216x4 - LayoutButton {INPUT} at (258,11) size 32x32 -layer at (334,129) size 216x4 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 216x4 [bgcolor=#00000033] -layer at (334,129) size 216x4 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 216x4 + LayoutSlider {INPUT} at (10,-1) size 280x56 [color=#9D968E] + LayoutFlexibleBox {DIV} at (16,26) size 248x4 +layer at (334,129) size 248x4 + LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 248x4 [bgcolor=#00000033] +layer at (334,129) size 248x4 + LayoutBlockFlow (positioned) {DIV} at (0,0) size 248x4 layer at (334,129) size 0x4 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x4 [bgcolor=#000000DE] layer at (334,129) size 0x4 @@ -82,13 +81,12 @@ LayoutFlexibleBox {DIV} at (0,0) size 300x54 [bgcolor=#F1F3F4] layer at (308,259) size 300x54 scrollHeight 55 LayoutFlexibleBox {DIV} at (0,0) size 300x54 - LayoutSlider {INPUT} at (10,-1) size 248x56 [color=#9D968E] - LayoutFlexibleBox {DIV} at (16,26) size 216x4 - LayoutButton {INPUT} at (258,11) size 32x32 -layer at (334,284) size 216x4 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 216x4 [bgcolor=#00000033] -layer at (334,284) size 216x4 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 216x4 + LayoutSlider {INPUT} at (10,-1) size 280x56 [color=#9D968E] + LayoutFlexibleBox {DIV} at (16,26) size 248x4 +layer at (334,284) size 248x4 + LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 248x4 [bgcolor=#00000033] +layer at (334,284) size 248x4 + LayoutBlockFlow (positioned) {DIV} at (0,0) size 248x4 layer at (334,284) size 0x4 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x4 [bgcolor=#000000DE] layer at (334,284) size 0x4
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.png index 3b15efd..a9868aa 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.txt index 250c2ab..0f8ed2e3 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.txt
@@ -13,16 +13,13 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 300x150 layer at (8,8) size 300x150 LayoutFlexibleBox {DIV} at (0,0) size 300x150 -layer at (114,27) size 88x88 - LayoutButton (positioned) {INPUT} at (106,19) size 88x88 - LayoutBlockFlow (anonymous) at (20,20) size 48x48 - LayoutBlockFlow {DIV} at (0,0) size 48x48 [bgcolor=#FFFFFFE6] layer at (8,86) size 300x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,78) size 300x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (44,48) size 160x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (76,48) size 128x0 layer at (212,86) size 48x48 transparent LayoutButton {INPUT} at (204,0) size 48x48 [color=#808080] layer at (260,86) size 48x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.png index ba6b2a0..51f69271 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.txt index a9b0006..0b2b901 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-controls-rendering-expected.txt
@@ -22,19 +22,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -70,19 +67,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,284) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,342) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,452) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -120,19 +114,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,524) size 320x240 backgroundClip at (8,524) size 320x76 clip at (8,524) size 320x76 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,582) size 100x100 backgroundClip at (118,582) size 100x18 clip at (118,582) size 100x18 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,692) size 320x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.png index 66c0d6f..d6e30d2 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.txt index ec3ccd9..42ebcb0 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-display-toggle-expected.txt
@@ -16,19 +16,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,28) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,86) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,196) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-empty-source-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-empty-source-expected.png index 12d0f5f..8e2e3c1 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-empty-source-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-empty-source-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-empty-source-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-empty-source-expected.txt index 0da22bb..1b9541c5 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-empty-source-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-empty-source-expected.txt
@@ -17,17 +17,14 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 300x150 layer at (9,45) size 300x150 LayoutFlexibleBox {DIV} at (0,0) size 300x150 -layer at (115,64) size 88x88 - LayoutButton (positioned) {INPUT} at (106,19) size 88x88 - LayoutBlockFlow (anonymous) at (20,20) size 48x48 -layer at (135,84) size 48x48 transparent - LayoutBlockFlow {DIV} at (0,0) size 48x48 [bgcolor=#FFFFFFE6] layer at (9,123) size 300x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,78) size 300x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (44,48) size 112x0 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (76,48) size 80x0 +layer at (9,123) size 48x48 transparent + LayoutButton {INPUT} at (0,0) size 48x48 [color=#808080] layer at (165,123) size 48x48 transparent LayoutButton {INPUT} at (156,0) size 48x48 [color=#808080] layer at (213,123) size 48x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.png index bc09186..bb9aa8b3 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.txt index 372a8d1..ab203036 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-no-audio-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 352x288 layer at (8,44) size 352x288 LayoutFlexibleBox {DIV} at (0,0) size 352x288 -layer at (128,120) size 112x112 - LayoutButton (positioned) {INPUT} at (120,76) size 112x112 - LayoutBlockFlow (anonymous) at (20,20) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] layer at (8,260) size 352x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,216) size 352x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (84,48) size 124x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (116,48) size 92x0 LayoutButton {INPUT} at (256,0) size 48x48 LayoutButton {INPUT} at (304,0) size 48x48 layer at (216,260) size 48x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.png index 1e845cb..6201165 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.txt index 7bc22b6..be34eb7f 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/video-zoom-controls-expected.txt
@@ -15,34 +15,22 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 layer at (57,85) size 240x180 LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (111,91) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (57,157) size 240x72 scrollWidth 330 +layer at (57,157) size 240x72 LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 42x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x24 - text run at (0,21) width 42: "0:00" - LayoutBlockFlow {DIV} at (72,-60) size 42x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 42: "0:06" - LayoutBlockFlow {DIV} at (114,72) size 0x0 - LayoutButton {INPUT} at (114,0) size 72x72 - LayoutButton {INPUT} at (186,0) size 72x72 - LayoutButton {INPUT} at (258,0) size 72x72 -layer at (171,157) size 0x72 transparent - LayoutSlider {INPUT} at (114,0) size 0x72 [color=#9D968E] + LayoutButton {INPUT} at (0,0) size 72x72 + LayoutBlockFlow {DIV} at (72,72) size 96x0 + LayoutButton {INPUT} at (168,0) size 72x72 +layer at (225,157) size 0x72 transparent + LayoutSlider {INPUT} at (168,0) size 0x72 [color=#9D968E] LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (171,190) size 18x6 +layer at (225,190) size 18x6 LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (171,190) size 18x6 scrollWidth 27 +layer at (225,190) size 18x6 scrollWidth 27 LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (171,190) size 0x6 +layer at (225,190) size 0x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (171,190) size 27x6 backgroundClip at (171,190) size 18x6 clip at (171,190) size 18x6 +layer at (225,190) size 27x6 backgroundClip at (225,190) size 18x6 clip at (225,190) size 18x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] layer at (57,229) size 240x36 LayoutSlider {INPUT} at (0,144) size 240x36 [color=#9D968E] @@ -66,34 +54,22 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 layer at (43,291) size 268x218 clip at (43,291) size 240x180 LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (104,306) size 153x153 clip at (104,306) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (49,361) size 249x113 clip at (49,361) size 240x72 scrollWidth 330 +layer at (49,361) size 249x113 clip at (49,361) size 240x72 LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 42x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x24 - text run at (0,21) width 42: "0:00" - LayoutBlockFlow {DIV} at (72,-60) size 42x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 42: "0:06" - LayoutBlockFlow {DIV} at (114,72) size 0x0 - LayoutButton {INPUT} at (114,0) size 72x72 - LayoutButton {INPUT} at (186,0) size 72x72 - LayoutButton {INPUT} at (258,0) size 72x72 -layer at (162,381) size 12x71 transparent - LayoutSlider {INPUT} at (114,0) size 0x72 [color=#9D968E] + LayoutButton {INPUT} at (0,0) size 72x72 + LayoutBlockFlow {DIV} at (72,72) size 96x0 + LayoutButton {INPUT} at (168,0) size 72x72 +layer at (215,391) size 12x71 transparent + LayoutSlider {INPUT} at (168,0) size 0x72 [color=#9D968E] LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (167,414) size 19x9 +layer at (221,423) size 18x9 LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (167,414) size 19x9 clip at (167,414) size 18x6 scrollWidth 27 +layer at (221,423) size 18x9 clip at (221,423) size 18x6 scrollWidth 27 LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (167,414) size 2x6 +layer at (221,423) size 1x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (167,414) size 28x10 backgroundClip at (167,414) size 19x9 clip at (167,414) size 19x9 +layer at (221,423) size 27x11 backgroundClip at (221,423) size 18x9 clip at (221,423) size 18x9 LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] layer at (43,432) size 243x77 LayoutSlider {INPUT} at (0,144) size 240x36 [color=#9D968E]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/media/video-zoom-controls-expected.png deleted file mode 100644 index f786942..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/media/video-zoom-controls-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/video-surface-layer/media/video-zoom-controls-expected.png deleted file mode 100644 index a28f8fab..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/video-surface-layer/media/video-zoom-controls-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/compositing/video/video-controls-layer-creation-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/compositing/video/video-controls-layer-creation-expected.png index eeb3ddc..e7d3ff7 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/compositing/video/video-controls-layer-creation-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/compositing/video/video-controls-layer-creation-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/fast/overflow/overflow-of-video-outline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/fast/overflow/overflow-of-video-outline-expected.png index 1b248183..c59ff35 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/fast/overflow/overflow-of-video-outline-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/fast/overflow/overflow-of-video-outline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-after-reload-expected.png index 9117e226..86276bb 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-after-reload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-after-reload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png index ae76971..ee415f0 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-strict-expected.png index 58207902..83d0ebfa 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-styling-expected.png index 60b94b8..df2a7f2a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-styling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-styling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-styling-strict-expected.png index 33690f9..ccf39e5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-styling-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-styling-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-without-preload-expected.png index e73e31d..4a55d10 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-without-preload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-without-preload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png index 20644d0..f5398dc8 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls/paint-controls-webkit-appearance-none-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls/paint-controls-webkit-appearance-none-expected.png index 20644d0..c1a23f7d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls/paint-controls-webkit-appearance-none-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls/paint-controls-webkit-appearance-none-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png index 8cc5110..b907545 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-grey-scrubber-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-grey-scrubber-expected.png index 5dd371d..69170764 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-grey-scrubber-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-grey-scrubber-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-controls-rendering-expected.png index 004affd..7b7848d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-display-toggle-expected.png index 05eac13e..897023e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-display-toggle-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-display-toggle-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-empty-source-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-empty-source-expected.png index 62ae15e..2550ff8 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-empty-source-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-empty-source-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-no-audio-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-no-audio-expected.png index 1bc397b..2557d3e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-no-audio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-no-audio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-zoom-controls-expected.png index 336cd246..0462bbf 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png index 20644d0..f5398dc8 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.png index 20644d0..c1a23f7d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/new-remote-playback-pipeline/media/controls/paint-controls-webkit-appearance-none-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-after-reload-expected.png index 1eaa335..f23c766 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-after-reload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-after-reload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png index ae76971..ee415f0 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-strict-expected.png index 08598ecd..918138b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-expected.png index 587cdf71..2a62ad5 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-strict-expected.png index 081f1fe0..14c39a3 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-styling-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-without-preload-expected.png index c62e66f..e43fdb7 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-without-preload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-without-preload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png index 8cc5110..b907545 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.png index 5dd371d..69170764 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-grey-scrubber-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-controls-rendering-expected.png index 8e42b2b..ce354585f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-display-toggle-expected.png index c9f86b4..bd14330 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-display-toggle-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-display-toggle-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-empty-source-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-empty-source-expected.png index 62ae15e..2550ff8 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-empty-source-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-empty-source-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png index 557f42884..947ca89 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-controls-layer-creation-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-controls-layer-creation-expected.png index f2001dc..6f1d074 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-controls-layer-creation-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-controls-layer-creation-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/overflow/overflow-of-video-outline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/overflow/overflow-of-video-outline-expected.png index c8631bd..676354f2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/overflow/overflow-of-video-outline-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/overflow/overflow-of-video-outline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls-after-reload-expected.png index 05a9d16..e7bd7cc 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-after-reload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-after-reload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-after-reload-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls-after-reload-expected.txt index 234ca03..ccc5608 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-after-reload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-after-reload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,42) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,100) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,210) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 141.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 109.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,210) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png index 0862e85..41f88b6e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls-strict-expected.png index 2df02901..b84d92af 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls-strict-expected.txt index dc9fd62..84d2af2 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-strict-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,50) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,108) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,218) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 141.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 109.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,218) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-expected.png index 8fd38ecad..7804a7c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-expected.txt index 6cd702a6..7608023d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (18,42) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (128,100) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (18,210) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 65.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 66x16 - text run at (0,14) width 66: "/ 0:06" - LayoutBlockFlow {DIV} at (112.28,48) size 111.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 65.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 66x16 + text run at (0,16) width 66: "/ 0:06" + LayoutBlockFlow {DIV} at (144.28,48) size 79.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (242,210) size 0x48 transparent @@ -68,19 +65,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,282) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,340) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,450) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 141.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 109.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,450) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-strict-expected.png index 0a2cbe62..0d46dcb 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-strict-expected.txt index cc003e6..88e6c08 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-styling-strict-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,50) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,108) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,218) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 141.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 109.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,218) size 0x48 transparent @@ -68,19 +65,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (332,50) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (442,108) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (332,218) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 141.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 109.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (556,218) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls-without-preload-expected.png index 695be562c..d32f00c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-without-preload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-without-preload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-without-preload-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls-without-preload-expected.txt index c7910e7..5ee8ca90 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-without-preload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-without-preload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,42) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,100) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,210) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 141.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 109.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,210) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/lazy-loaded-style-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls/lazy-loaded-style-expected.txt index 0239b40..7702252 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls/lazy-loaded-style-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/lazy-loaded-style-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x300 layer at (8,8) size 400x300 LayoutFlexibleBox {DIV} at (0,0) size 400x300 -layer at (151,89) size 115x115 - LayoutButton (positioned) {INPUT} at (142.50,80.50) size 115x115 - LayoutBlockFlow (anonymous) at (20,20) size 75x75 - LayoutBlockFlow {DIV} at (0,0) size 75x75 [bgcolor=#FFFFFFE6] layer at (8,236) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,228) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 221.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 189.72x0 LayoutButton {INPUT} at (304,0) size 48x48 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,236) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png index 93e28e1..d3de7e9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt index df4fb91..1459cbb4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x327.27 layer at (8,8) size 400x327 LayoutFlexibleBox {DIV} at (0,0) size 400x327.27 -layer at (147,99) size 122x122 - LayoutButton (positioned) {INPUT} at (139.13,90.75) size 121.75x121.75 - LayoutBlockFlow (anonymous) at (20,20) size 81.75x81.75 - LayoutBlockFlow {DIV} at (0,0) size 81.75x81.75 [bgcolor=#FFFFFFE6] layer at (8,263) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,255.27) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (82.28,48) size 221.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (114.28,48) size 189.72x0 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,263) size 48x48 transparent LayoutButton {INPUT} at (304,0) size 48x48 [color=#7F7F7F]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.png index 93e28e1..7dc5dcb 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.txt index df4fb91..1459cbb4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/paint-controls-webkit-appearance-none-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x327.27 layer at (8,8) size 400x327 LayoutFlexibleBox {DIV} at (0,0) size 400x327.27 -layer at (147,99) size 122x122 - LayoutButton (positioned) {INPUT} at (139.13,90.75) size 121.75x121.75 - LayoutBlockFlow (anonymous) at (20,20) size 81.75x81.75 - LayoutBlockFlow {DIV} at (0,0) size 81.75x81.75 [bgcolor=#FFFFFFE6] layer at (8,263) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,255.27) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (82.28,48) size 221.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (114.28,48) size 189.72x0 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,263) size 48x48 transparent LayoutButton {INPUT} at (304,0) size 48x48 [color=#7F7F7F]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png index e08b5ba..6fae837 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.txt index 5afb9bd..9ba2571 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.txt
@@ -42,13 +42,12 @@ LayoutFlexibleBox {DIV} at (0,0) size 300x54 [bgcolor=#F1F3F4] layer at (308,104) size 300x54 scrollHeight 55 LayoutFlexibleBox {DIV} at (0,0) size 300x54 - LayoutSlider {INPUT} at (10,-1) size 248x56 [color=#909090] - LayoutFlexibleBox {DIV} at (16,26) size 216x4 - LayoutButton {INPUT} at (258,11) size 32x32 -layer at (334,129) size 216x4 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 216x4 [bgcolor=#00000033] -layer at (334,129) size 216x4 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 216x4 + LayoutSlider {INPUT} at (10,-1) size 280x56 [color=#909090] + LayoutFlexibleBox {DIV} at (16,26) size 248x4 +layer at (334,129) size 248x4 + LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 248x4 [bgcolor=#00000033] +layer at (334,129) size 248x4 + LayoutBlockFlow (positioned) {DIV} at (0,0) size 248x4 layer at (334,129) size 0x4 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x4 [bgcolor=#000000DE] layer at (334,129) size 0x4 @@ -82,13 +81,12 @@ LayoutFlexibleBox {DIV} at (0,0) size 300x54 [bgcolor=#F1F3F4] layer at (308,258) size 300x54 scrollHeight 55 LayoutFlexibleBox {DIV} at (0,0) size 300x54 - LayoutSlider {INPUT} at (10,-1) size 248x56 [color=#909090] - LayoutFlexibleBox {DIV} at (16,26) size 216x4 - LayoutButton {INPUT} at (258,11) size 32x32 -layer at (334,283) size 216x4 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 216x4 [bgcolor=#00000033] -layer at (334,283) size 216x4 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 216x4 + LayoutSlider {INPUT} at (10,-1) size 280x56 [color=#909090] + LayoutFlexibleBox {DIV} at (16,26) size 248x4 +layer at (334,283) size 248x4 + LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 248x4 [bgcolor=#00000033] +layer at (334,283) size 248x4 + LayoutBlockFlow (positioned) {DIV} at (0,0) size 248x4 layer at (334,283) size 0x4 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x4 [bgcolor=#000000DE] layer at (334,283) size 0x4
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-grey-scrubber-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-grey-scrubber-expected.png index 467fb97..5cc4966 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-grey-scrubber-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-grey-scrubber-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-grey-scrubber-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-grey-scrubber-expected.txt index 4b6994a..e3ee427 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-grey-scrubber-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-grey-scrubber-expected.txt
@@ -13,16 +13,13 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 300x150 layer at (8,8) size 300x150 LayoutFlexibleBox {DIV} at (0,0) size 300x150 -layer at (114,27) size 88x88 - LayoutButton (positioned) {INPUT} at (106,19) size 88x88 - LayoutBlockFlow (anonymous) at (20,20) size 48x48 - LayoutBlockFlow {DIV} at (0,0) size 48x48 [bgcolor=#FFFFFFE6] layer at (8,86) size 300x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,78) size 300x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (43.25,48) size 160.75x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (75.25,48) size 128.75x0 layer at (212,86) size 48x48 transparent LayoutButton {INPUT} at (204,0) size 48x48 [color=#7F7F7F] layer at (260,86) size 48x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-controls-rendering-expected.png index a96a444..b9436e4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-controls-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/video-controls-rendering-expected.txt index 9b2361e..3330a368 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-controls-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-controls-rendering-expected.txt
@@ -22,19 +22,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,42) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,100) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,210) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 141.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 109.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,210) size 0x48 transparent @@ -69,19 +66,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,282) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,340) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,450) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 141.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 109.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,450) size 0x48 transparent @@ -118,19 +112,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,522) size 320x240 backgroundClip at (8,522) size 320x78 clip at (8,522) size 320x78 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,580) size 100x100 backgroundClip at (118,580) size 100x20 clip at (118,580) size 100x20 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,690) size 320x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 141.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 109.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,690) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-display-toggle-expected.png index 0eb1c2b..3795abc 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-display-toggle-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-display-toggle-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-display-toggle-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/video-display-toggle-expected.txt index 31c9da1f..3bf0b40 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-display-toggle-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-display-toggle-expected.txt
@@ -16,19 +16,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,26) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,84) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,194) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 141.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 109.72x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,194) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-empty-source-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-empty-source-expected.png index 302ad884..1d9f54a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-empty-source-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-empty-source-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-empty-source-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/video-empty-source-expected.txt index b3469148..b474ca6e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-empty-source-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-empty-source-expected.txt
@@ -17,17 +17,14 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 300x150 layer at (9,43) size 300x150 LayoutFlexibleBox {DIV} at (0,0) size 300x150 -layer at (115,62) size 88x88 - LayoutButton (positioned) {INPUT} at (106,19) size 88x88 - LayoutBlockFlow (anonymous) at (20,20) size 48x48 -layer at (135,82) size 48x48 transparent - LayoutBlockFlow {DIV} at (0,0) size 48x48 [bgcolor=#FFFFFFE6] layer at (9,121) size 300x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,78) size 300x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (43.25,48) size 112.75x0 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (75.25,48) size 80.75x0 +layer at (9,121) size 48x48 transparent + LayoutButton {INPUT} at (0,0) size 48x48 [color=#7F7F7F] layer at (165,121) size 48x48 transparent LayoutButton {INPUT} at (156,0) size 48x48 [color=#7F7F7F] layer at (213,121) size 48x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-no-audio-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-no-audio-expected.png index 56ec42d3..2443723 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-no-audio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-no-audio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-no-audio-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/video-no-audio-expected.txt index bb05e7a..66636d6 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-no-audio-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-no-audio-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 352x288 layer at (8,42) size 352x288 LayoutFlexibleBox {DIV} at (0,0) size 352x288 -layer at (128,118) size 112x112 - LayoutButton (positioned) {INPUT} at (120,76) size 112x112 - LayoutBlockFlow (anonymous) at (20,20) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] layer at (8,258) size 352x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,216) size 352x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (82.28,48) size 173.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (114.28,48) size 141.72x0 LayoutButton {INPUT} at (304,0) size 48x48 layer at (264,258) size 48x48 transparent LayoutButton {INPUT} at (256,0) size 48x48 [color=#7F7F7F]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png index 8ca4730..65ca7c7e 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt index 368eaff..51e8b9b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt
@@ -15,33 +15,22 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 layer at (57,85) size 240x180 LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (111,91) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (57,157) size 240x72 scrollWidth 256 +layer at (57,157) size 240x72 LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 40.88x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 41x24 - text run at (0,21) width 41: "0:00" - LayoutBlockFlow {DIV} at (70.88,-60) size 40.88x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 41x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 41: "0:06" - LayoutBlockFlow {DIV} at (111.75,72) size 0x0 - LayoutButton {INPUT} at (111.75,0) size 72x72 - LayoutButton {INPUT} at (183.75,0) size 72x72 -layer at (169,157) size 0x72 transparent - LayoutSlider {INPUT} at (111.75,0) size 0x72 [color=#909090] + LayoutButton {INPUT} at (0,0) size 72x72 + LayoutBlockFlow {DIV} at (72,72) size 96x0 + LayoutButton {INPUT} at (168,0) size 72x72 +layer at (225,157) size 0x72 transparent + LayoutSlider {INPUT} at (168,0) size 0x72 [color=#909090] LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (169,190) size 18x6 +layer at (225,190) size 18x6 LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (169,190) size 18x6 scrollWidth 27 +layer at (225,190) size 18x6 scrollWidth 27 LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (169,190) size 0x6 +layer at (225,190) size 0x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (169,190) size 27x6 backgroundClip at (169,190) size 18x6 clip at (169,190) size 18x6 +layer at (225,190) size 27x6 backgroundClip at (225,190) size 18x6 clip at (225,190) size 18x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] layer at (57,229) size 240x36 LayoutSlider {INPUT} at (0,144) size 240x36 [color=#909090] @@ -65,33 +54,22 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 layer at (43,291) size 268x218 clip at (43,291) size 240x180 LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (104,306) size 153x153 clip at (104,306) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (49,361) size 249x113 clip at (49,361) size 240x72 scrollWidth 256 +layer at (49,361) size 249x113 clip at (49,361) size 240x72 LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 40.88x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 41x24 - text run at (0,21) width 41: "0:00" - LayoutBlockFlow {DIV} at (70.88,-60) size 40.88x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 41x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 41: "0:06" - LayoutBlockFlow {DIV} at (111.75,72) size 0x0 - LayoutButton {INPUT} at (111.75,0) size 72x72 - LayoutButton {INPUT} at (183.75,0) size 72x72 -layer at (159,381) size 13x71 transparent - LayoutSlider {INPUT} at (111.75,0) size 0x72 [color=#909090] + LayoutButton {INPUT} at (0,0) size 72x72 + LayoutBlockFlow {DIV} at (72,72) size 96x0 + LayoutButton {INPUT} at (168,0) size 72x72 +layer at (215,391) size 12x71 transparent + LayoutSlider {INPUT} at (168,0) size 0x72 [color=#909090] LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (165,413) size 19x9 +layer at (221,423) size 18x9 LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (165,413) size 19x9 clip at (165,413) size 18x6 scrollWidth 27 +layer at (221,423) size 18x9 clip at (221,423) size 18x6 scrollWidth 27 LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (165,413) size 1x6 +layer at (221,423) size 1x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (165,413) size 28x11 backgroundClip at (165,413) size 19x9 clip at (165,413) size 19x9 +layer at (221,423) size 27x11 backgroundClip at (221,423) size 18x9 clip at (221,423) size 18x9 LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] layer at (43,432) size 243x77 LayoutSlider {INPUT} at (0,144) size 240x36 [color=#909090]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.png index ff76c075..3166d16 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.txt index 7313fec..ec38389 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-after-reload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,42) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,100) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,210) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 93.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 61.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.png index 6df2a7b..1232bba86 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.txt index ca359621..a6b0496 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-strict-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,50) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,108) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,218) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 93.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 61.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.png index a6f86d9b..70870275 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.txt index c4383e6..d23718f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (18,42) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (128,100) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (18,210) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 65.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 66x16 - text run at (0,14) width 66: "/ 0:06" - LayoutBlockFlow {DIV} at (112.28,48) size 63.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 65.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 66x16 + text run at (0,16) width 66: "/ 0:06" + LayoutBlockFlow {DIV} at (144.28,48) size 31.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -69,19 +66,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,282) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,340) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,450) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 93.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 61.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.png index 19624bc..c74ab967 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.txt index 12d4853..960af0f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-styling-strict-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,50) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,108) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,218) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 93.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 61.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -69,19 +66,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (332,50) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (442,108) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (332,218) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 93.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 61.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.png index 7ec320d..1d20bca 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.txt index 3a95ed9..ebebdde 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/controls-without-preload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,42) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,100) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,210) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 93.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 61.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.png index 04e720b..5c4be3a 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.txt index 15b32fd..fe171ae 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-controls-rendering-expected.txt
@@ -22,19 +22,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,42) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,100) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,210) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 93.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 61.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -70,19 +67,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,282) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,340) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,450) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 93.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 61.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -120,19 +114,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,522) size 320x240 backgroundClip at (8,522) size 320x78 clip at (8,522) size 320x78 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,580) size 100x100 backgroundClip at (118,580) size 100x20 clip at (118,580) size 100x20 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,690) size 320x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 93.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 61.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.png index 389d207..61bab506 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.txt index 9d4ff732..0b7a2ad 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-display-toggle-expected.txt
@@ -16,19 +16,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,26) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,84) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,194) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 27.25x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (47.25,4) size 35.03x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (82.28,48) size 93.72x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 27.25x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (79.25,0) size 35.03x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (114.28,48) size 61.72x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png index 6494d7f8..058e324 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.txt deleted file mode 100644 index de9743c..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.txt +++ /dev/null
@@ -1,110 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutBlockFlow {HTML} at (0,0) size 800x600 - LayoutBlockFlow {BODY} at (12,12) size 776x543 - LayoutBlockFlow {P} at (0,0) size 776x28 - LayoutText {#text} at (0,0) size 278x28 - text run at (0,0) width 278: "Zoomed video with controls." -layer at (57,85) size 240x180 - LayoutVideo {VIDEO} at (45,73) size 240x180 -layer at (57,85) size 240x180 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 - LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (57,85) size 240x180 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 -layer at (57,85) size 240x180 - LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (111,91) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (57,157) size 240x72 scrollWidth 328 - LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 40.88x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 41x24 - text run at (0,21) width 41: "0:00" - LayoutBlockFlow {DIV} at (70.88,-60) size 40.88x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 41x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 41: "0:06" - LayoutBlockFlow {DIV} at (111.75,72) size 0x0 - LayoutButton {INPUT} at (111.75,0) size 72x72 - LayoutButton {INPUT} at (183.75,0) size 72x72 - LayoutButton {INPUT} at (255.75,0) size 72x72 -layer at (169,157) size 0x72 transparent - LayoutSlider {INPUT} at (111.75,0) size 0x72 [color=#909090] - LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (169,190) size 18x6 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] - LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (169,190) size 18x6 scrollWidth 27 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (169,190) size 0x6 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (169,190) size 27x6 backgroundClip at (169,190) size 18x6 clip at (169,190) size 18x6 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] -layer at (57,229) size 240x36 - LayoutSlider {INPUT} at (0,144) size 240x36 [color=#909090] - LayoutFlexibleBox {DIV} at (24,0) size 192x6 -layer at (81,229) size 192x6 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 192x6 [bgcolor=#FFFFFF4D] -layer at (81,223) size 18x18 - LayoutBlockFlow (relative positioned) {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (81,229) size 192x6 scrollWidth 288 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 192x6 -layer at (81,229) size 0x6 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (81,229) size 288x6 backgroundClip at (81,229) size 192x6 clip at (81,229) size 192x6 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 288x6 [bgcolor=#FFFFFF8A] -layer at (57,310) size 240x180 - LayoutVideo {VIDEO} at (45,298) size 240x180 -layer at (43,291) size 268x218 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 - LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (43,291) size 268x218 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 -layer at (43,291) size 268x218 clip at (43,291) size 240x180 - LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (104,306) size 153x153 clip at (104,306) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (49,361) size 249x113 clip at (49,361) size 240x72 scrollWidth 328 - LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 40.88x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 41x24 - text run at (0,21) width 41: "0:00" - LayoutBlockFlow {DIV} at (70.88,-60) size 40.88x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 41x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 41: "0:06" - LayoutBlockFlow {DIV} at (111.75,72) size 0x0 - LayoutButton {INPUT} at (111.75,0) size 72x72 - LayoutButton {INPUT} at (183.75,0) size 72x72 - LayoutButton {INPUT} at (255.75,0) size 72x72 -layer at (159,381) size 13x71 transparent - LayoutSlider {INPUT} at (111.75,0) size 0x72 [color=#909090] - LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (165,413) size 19x9 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] - LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (165,413) size 19x9 clip at (165,413) size 18x6 scrollWidth 27 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (165,413) size 1x6 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (165,413) size 28x11 backgroundClip at (165,413) size 19x9 clip at (165,413) size 19x9 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] -layer at (43,432) size 243x77 - LayoutSlider {INPUT} at (0,144) size 240x36 [color=#909090] - LayoutFlexibleBox {DIV} at (24,0) size 192x6 -layer at (72,437) size 190x39 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 192x6 [bgcolor=#FFFFFF4D] -layer at (71,431) size 21x20 - LayoutBlockFlow (relative positioned) {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (72,437) size 190x39 clip at (72,437) size 190x6 scrollWidth 288 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 192x6 -layer at (72,437) size 1x5 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (72,437) size 285x55 backgroundClip at (72,437) size 190x39 clip at (72,437) size 190x39 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 288x6 [bgcolor=#FFFFFF8A]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/overflow/overflow-of-video-outline-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/overflow/overflow-of-video-outline-expected.png index 358a2398..641dbb8a 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/overflow/overflow-of-video-outline-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/overflow/overflow-of-video-outline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls-after-reload-expected.png index cfab8461..ec294b55 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-after-reload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-after-reload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-after-reload-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls-after-reload-expected.txt index 4afee15..5f6dcd6 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-after-reload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-after-reload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,212) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png index efe724818..e3be6c2 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls-strict-expected.png index f516aa485..d5f2e89b 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls-strict-expected.txt index b918b54..9152fb7 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-strict-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,220) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-expected.png index dd1ef6a..539cbac1 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-expected.txt index 2ef96fe..6c6cb89 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (18,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (128,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (18,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 66x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 66x16 - text run at (0,14) width 66: "/ 0:06" - LayoutBlockFlow {DIV} at (114,48) size 110x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 66x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 66x16 + text run at (0,16) width 66: "/ 0:06" + LayoutBlockFlow {DIV} at (146,48) size 78x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (242,212) size 0x48 transparent @@ -68,19 +65,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,284) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,342) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,452) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,452) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-strict-expected.png index 2dfdfb8d..870b219 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-strict-expected.txt index b0a7e915..31bff01 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-styling-strict-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,220) size 0x48 transparent @@ -68,19 +65,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (332,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (442,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (332,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (556,220) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls-without-preload-expected.png index 3ff9433..73a3fa9 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-without-preload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-without-preload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-without-preload-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls-without-preload-expected.txt index f7fa29b7..8c3c8a6 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls-without-preload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-without-preload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,212) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/lazy-loaded-style-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls/lazy-loaded-style-expected.txt index 45b6a1a..6943382 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls/lazy-loaded-style-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/lazy-loaded-style-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x300 layer at (8,8) size 400x300 LayoutFlexibleBox {DIV} at (0,0) size 400x300 -layer at (151,89) size 115x115 - LayoutButton (positioned) {INPUT} at (142.50,80.50) size 115x115 - LayoutBlockFlow (anonymous) at (20,20) size 75x75 - LayoutBlockFlow {DIV} at (0,0) size 75x75 [bgcolor=#FFFFFFE6] layer at (8,236) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,228) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 220x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 188x0 LayoutButton {INPUT} at (304,0) size 48x48 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,236) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png index 0a14ccf..5acc521 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt index b5f82f0..4451555 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-custom-bg-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x327.27 layer at (8,8) size 400x327 LayoutFlexibleBox {DIV} at (0,0) size 400x327.27 -layer at (147,99) size 122x122 - LayoutButton (positioned) {INPUT} at (139.13,90.75) size 121.75x121.75 - LayoutBlockFlow (anonymous) at (20,20) size 81.75x81.75 - LayoutBlockFlow {DIV} at (0,0) size 81.75x81.75 [bgcolor=#FFFFFFE6] layer at (8,263) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,255.27) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (84,48) size 220x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (116,48) size 188x0 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,263) size 48x48 transparent LayoutButton {INPUT} at (304,0) size 48x48 [color=#808080]
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.png index 0a14ccf..b34f451 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.txt index b5f82f0..4451555 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/paint-controls-webkit-appearance-none-expected.txt
@@ -13,19 +13,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 400x327.27 layer at (8,8) size 400x327 LayoutFlexibleBox {DIV} at (0,0) size 400x327.27 -layer at (147,99) size 122x122 - LayoutButton (positioned) {INPUT} at (139.13,90.75) size 121.75x121.75 - LayoutBlockFlow (anonymous) at (20,20) size 81.75x81.75 - LayoutBlockFlow {DIV} at (0,0) size 81.75x81.75 [bgcolor=#FFFFFFE6] layer at (8,263) size 400x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,255.27) size 400x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (84,48) size 220x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (116,48) size 188x0 LayoutButton {INPUT} at (352,0) size 48x48 layer at (312,263) size 48x48 transparent LayoutButton {INPUT} at (304,0) size 48x48 [color=#808080]
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png index 81bcf379..7f91881a 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.txt index 6e9089f..cbe76da8 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.txt
@@ -42,13 +42,12 @@ LayoutFlexibleBox {DIV} at (0,0) size 300x54 [bgcolor=#F1F3F4] layer at (308,104) size 300x54 scrollHeight 55 LayoutFlexibleBox {DIV} at (0,0) size 300x54 - LayoutSlider {INPUT} at (10,-1) size 248x56 [color=#C4C4C4] - LayoutFlexibleBox {DIV} at (16,26) size 216x4 - LayoutButton {INPUT} at (258,11) size 32x32 -layer at (334,129) size 216x4 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 216x4 [bgcolor=#00000033] -layer at (334,129) size 216x4 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 216x4 + LayoutSlider {INPUT} at (10,-1) size 280x56 [color=#C4C4C4] + LayoutFlexibleBox {DIV} at (16,26) size 248x4 +layer at (334,129) size 248x4 + LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 248x4 [bgcolor=#00000033] +layer at (334,129) size 248x4 + LayoutBlockFlow (positioned) {DIV} at (0,0) size 248x4 layer at (334,129) size 0x4 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x4 [bgcolor=#000000DE] layer at (334,129) size 0x4 @@ -82,13 +81,12 @@ LayoutFlexibleBox {DIV} at (0,0) size 300x54 [bgcolor=#F1F3F4] layer at (308,259) size 300x54 scrollHeight 55 LayoutFlexibleBox {DIV} at (0,0) size 300x54 - LayoutSlider {INPUT} at (10,-1) size 248x56 [color=#C4C4C4] - LayoutFlexibleBox {DIV} at (16,26) size 216x4 - LayoutButton {INPUT} at (258,11) size 32x32 -layer at (334,284) size 216x4 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 216x4 [bgcolor=#00000033] -layer at (334,284) size 216x4 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 216x4 + LayoutSlider {INPUT} at (10,-1) size 280x56 [color=#C4C4C4] + LayoutFlexibleBox {DIV} at (16,26) size 248x4 +layer at (334,284) size 248x4 + LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 248x4 [bgcolor=#00000033] +layer at (334,284) size 248x4 + LayoutBlockFlow (positioned) {DIV} at (0,0) size 248x4 layer at (334,284) size 0x4 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x4 [bgcolor=#000000DE] layer at (334,284) size 0x4
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-grey-scrubber-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-grey-scrubber-expected.png index 47562f8..1596127 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-grey-scrubber-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-grey-scrubber-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-grey-scrubber-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-grey-scrubber-expected.txt index b414d9d..e62d1399 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-grey-scrubber-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-grey-scrubber-expected.txt
@@ -13,16 +13,13 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 300x150 layer at (8,8) size 300x150 LayoutFlexibleBox {DIV} at (0,0) size 300x150 -layer at (114,27) size 88x88 - LayoutButton (positioned) {INPUT} at (106,19) size 88x88 - LayoutBlockFlow (anonymous) at (20,20) size 48x48 - LayoutBlockFlow {DIV} at (0,0) size 48x48 [bgcolor=#FFFFFFE6] layer at (8,86) size 300x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,78) size 300x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (44,48) size 160x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (76,48) size 128x0 layer at (212,86) size 48x48 transparent LayoutButton {INPUT} at (204,0) size 48x48 [color=#808080] layer at (260,86) size 48x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-controls-rendering-expected.png index c7df7308..9cd5b09 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-controls-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/video-controls-rendering-expected.txt index 8c638bf..e5811c9 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-controls-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-controls-rendering-expected.txt
@@ -22,19 +22,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,212) size 0x48 transparent @@ -69,19 +66,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,284) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,342) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,452) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,452) size 0x48 transparent @@ -118,19 +112,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,524) size 320x240 backgroundClip at (8,524) size 320x76 clip at (8,524) size 320x76 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,582) size 100x100 backgroundClip at (118,582) size 100x18 clip at (118,582) size 100x18 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,692) size 320x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,692) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-display-toggle-expected.png index 5d0e38e..fbb8785 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-display-toggle-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-display-toggle-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-display-toggle-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/video-display-toggle-expected.txt index 2a7de13..dffd5692 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-display-toggle-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-display-toggle-expected.txt
@@ -16,19 +16,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,28) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,86) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,196) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 140x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 108x0 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 layer at (232,196) size 0x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-empty-source-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-empty-source-expected.png index dc20421..c5e9eec 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-empty-source-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-empty-source-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-empty-source-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/video-empty-source-expected.txt index c426dc3..93785723 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-empty-source-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-empty-source-expected.txt
@@ -17,17 +17,14 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 300x150 layer at (9,45) size 300x150 LayoutFlexibleBox {DIV} at (0,0) size 300x150 -layer at (115,64) size 88x88 - LayoutButton (positioned) {INPUT} at (106,19) size 88x88 - LayoutBlockFlow (anonymous) at (20,20) size 48x48 -layer at (135,84) size 48x48 transparent - LayoutBlockFlow {DIV} at (0,0) size 48x48 [bgcolor=#FFFFFFE6] layer at (9,123) size 300x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,78) size 300x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (44,48) size 112x0 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (76,48) size 80x0 +layer at (9,123) size 48x48 transparent + LayoutButton {INPUT} at (0,0) size 48x48 [color=#808080] layer at (165,123) size 48x48 transparent LayoutButton {INPUT} at (156,0) size 48x48 [color=#808080] layer at (213,123) size 48x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-no-audio-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-no-audio-expected.png index 5fc61f3..64235ca 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-no-audio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-no-audio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-no-audio-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/video-no-audio-expected.txt index ac6e20a..89f06c9 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-no-audio-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-no-audio-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 352x288 layer at (8,44) size 352x288 LayoutFlexibleBox {DIV} at (0,0) size 352x288 -layer at (128,120) size 112x112 - LayoutButton (positioned) {INPUT} at (120,76) size 112x112 - LayoutBlockFlow (anonymous) at (20,20) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] layer at (8,260) size 352x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,216) size 352x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (84,48) size 172x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (116,48) size 140x0 LayoutButton {INPUT} at (304,0) size 48x48 layer at (264,260) size 48x48 transparent LayoutButton {INPUT} at (256,0) size 48x48 [color=#808080]
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png index 291b643..f1043561d0 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.txt index 98970df..dae47559 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.txt
@@ -15,33 +15,22 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 layer at (57,85) size 240x180 LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (111,91) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (57,157) size 240x72 scrollWidth 258 +layer at (57,157) size 240x72 LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 42x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x24 - text run at (0,21) width 42: "0:00" - LayoutBlockFlow {DIV} at (72,-60) size 42x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 42: "0:06" - LayoutBlockFlow {DIV} at (114,72) size 0x0 - LayoutButton {INPUT} at (114,0) size 72x72 - LayoutButton {INPUT} at (186,0) size 72x72 -layer at (171,157) size 0x72 transparent - LayoutSlider {INPUT} at (114,0) size 0x72 [color=#C4C4C4] + LayoutButton {INPUT} at (0,0) size 72x72 + LayoutBlockFlow {DIV} at (72,72) size 96x0 + LayoutButton {INPUT} at (168,0) size 72x72 +layer at (225,157) size 0x72 transparent + LayoutSlider {INPUT} at (168,0) size 0x72 [color=#C4C4C4] LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (171,190) size 18x6 +layer at (225,190) size 18x6 LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (171,190) size 18x6 scrollWidth 27 +layer at (225,190) size 18x6 scrollWidth 27 LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (171,190) size 0x6 +layer at (225,190) size 0x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (171,190) size 27x6 backgroundClip at (171,190) size 18x6 clip at (171,190) size 18x6 +layer at (225,190) size 27x6 backgroundClip at (225,190) size 18x6 clip at (225,190) size 18x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] layer at (57,229) size 240x36 LayoutSlider {INPUT} at (0,144) size 240x36 [color=#C4C4C4] @@ -65,33 +54,22 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 layer at (43,291) size 268x218 clip at (43,291) size 240x180 LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (104,306) size 153x153 clip at (104,306) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (49,361) size 249x113 clip at (49,361) size 240x72 scrollWidth 258 +layer at (49,361) size 249x113 clip at (49,361) size 240x72 LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 42x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x24 - text run at (0,21) width 42: "0:00" - LayoutBlockFlow {DIV} at (72,-60) size 42x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 42: "0:06" - LayoutBlockFlow {DIV} at (114,72) size 0x0 - LayoutButton {INPUT} at (114,0) size 72x72 - LayoutButton {INPUT} at (186,0) size 72x72 -layer at (162,381) size 12x71 transparent - LayoutSlider {INPUT} at (114,0) size 0x72 [color=#C4C4C4] + LayoutButton {INPUT} at (0,0) size 72x72 + LayoutBlockFlow {DIV} at (72,72) size 96x0 + LayoutButton {INPUT} at (168,0) size 72x72 +layer at (215,391) size 12x71 transparent + LayoutSlider {INPUT} at (168,0) size 0x72 [color=#C4C4C4] LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (167,414) size 19x9 +layer at (221,423) size 18x9 LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (167,414) size 19x9 clip at (167,414) size 18x6 scrollWidth 27 +layer at (221,423) size 18x9 clip at (221,423) size 18x6 scrollWidth 27 LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (167,414) size 2x6 +layer at (221,423) size 1x6 LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (167,414) size 28x10 backgroundClip at (167,414) size 19x9 clip at (167,414) size 19x9 +layer at (221,423) size 27x11 backgroundClip at (221,423) size 18x9 clip at (221,423) size 18x9 LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] layer at (43,432) size 243x77 LayoutSlider {INPUT} at (0,144) size 240x36 [color=#C4C4C4]
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.png index 09e9939b..54b8c22 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.txt index 54d48a6b..aa176f35 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-after-reload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.png index af5565f..c18b578 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.txt index 1bf1fb5..2e6dd43 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-strict-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.png index a800a55..bd7c6c4 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.txt index 76ff76fe..eda6d2c1 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (18,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (128,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (18,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 66x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 66x16 - text run at (0,14) width 66: "/ 0:06" - LayoutBlockFlow {DIV} at (114,48) size 62x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 66x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 66x16 + text run at (0,16) width 66: "/ 0:06" + LayoutBlockFlow {DIV} at (146,48) size 30x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -69,19 +66,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,284) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,342) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,452) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.png index 23d7e83..79086fa 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.txt index 45bacc33..5db283d 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-styling-strict-expected.txt
@@ -21,19 +21,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -69,19 +66,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (332,52) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (442,110) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (332,220) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.png index 276c9d6..b99686f5 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.txt index a4e2426..97e58fb 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/controls-without-preload-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.png index a967d269..2008981 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.txt index 4ce55d8..13e2174f13 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-controls-rendering-expected.txt
@@ -22,19 +22,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,44) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,102) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,212) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -70,19 +67,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,284) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,342) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,452) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48 @@ -120,19 +114,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,524) size 320x240 backgroundClip at (8,524) size 320x76 clip at (8,524) size 320x76 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,582) size 100x100 backgroundClip at (118,582) size 100x18 clip at (118,582) size 100x18 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,692) size 320x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.png index af8c0cf..e000e22 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.txt index 1c3d168..63bc16b 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-display-toggle-expected.txt
@@ -16,19 +16,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 320x240 layer at (8,28) size 320x240 LayoutFlexibleBox {DIV} at (0,0) size 320x240 -layer at (118,86) size 100x100 - LayoutButton (positioned) {INPUT} at (110,58) size 100x100 - LayoutBlockFlow (anonymous) at (20,20) size 60x60 - LayoutBlockFlow {DIV} at (0,0) size 60x60 [bgcolor=#FFFFFFE6] layer at (8,196) size 320x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,168) size 320x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:06" - LayoutBlockFlow {DIV} at (84,48) size 92x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:06" + LayoutBlockFlow {DIV} at (116,48) size 60x0 LayoutButton {INPUT} at (176,0) size 48x48 LayoutButton {INPUT} at (224,0) size 48x48 LayoutButton {INPUT} at (272,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.png index 568b112..ffbabb6 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.txt index 99dfb36..a6a3eae4 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-no-audio-expected.txt
@@ -17,19 +17,16 @@ LayoutBlockFlow (positioned) {DIV} at (0,0) size 352x288 layer at (8,44) size 352x288 LayoutFlexibleBox {DIV} at (0,0) size 352x288 -layer at (128,120) size 112x112 - LayoutButton (positioned) {INPUT} at (120,76) size 112x112 - LayoutBlockFlow (anonymous) at (20,20) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] layer at (8,260) size 352x48 LayoutFlexibleBox (relative positioned) {DIV} at (0,216) size 352x48 - LayoutBlockFlow {DIV} at (16,4) size 28x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 28x16 - text run at (0,14) width 28: "0:00" - LayoutBlockFlow {DIV} at (48,4) size 36x44 [color=#FFFFFF] - LayoutText {#text} at (0,14) size 36x16 - text run at (0,14) width 36: "/ 0:09" - LayoutBlockFlow {DIV} at (84,48) size 124x0 + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutBlockFlow {DIV} at (48,0) size 28x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 28x16 + text run at (0,16) width 28: "0:00" + LayoutBlockFlow {DIV} at (80,0) size 36x48 [color=#FFFFFF] + LayoutText {#text} at (0,16) size 36x16 + text run at (0,16) width 36: "/ 0:09" + LayoutBlockFlow {DIV} at (116,48) size 92x0 LayoutButton {INPUT} at (256,0) size 48x48 LayoutButton {INPUT} at (304,0) size 48x48 layer at (216,260) size 48x48 transparent
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.png index a92b7e0..b6d0785 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.txt deleted file mode 100644 index dd0be87..0000000 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/video-surface-layer/media/video-zoom-controls-expected.txt +++ /dev/null
@@ -1,110 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutBlockFlow {HTML} at (0,0) size 800x600 - LayoutBlockFlow {BODY} at (12,12) size 776x543 - LayoutBlockFlow {P} at (0,0) size 776x28 - LayoutText {#text} at (0,0) size 275x27 - text run at (0,0) width 275: "Zoomed video with controls." -layer at (57,85) size 240x180 - LayoutVideo {VIDEO} at (45,73) size 240x180 -layer at (57,85) size 240x180 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 - LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (57,85) size 240x180 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 -layer at (57,85) size 240x180 - LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (111,91) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (57,157) size 240x72 scrollWidth 330 - LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 42x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x24 - text run at (0,21) width 42: "0:00" - LayoutBlockFlow {DIV} at (72,-60) size 42x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 42: "0:06" - LayoutBlockFlow {DIV} at (114,72) size 0x0 - LayoutButton {INPUT} at (114,0) size 72x72 - LayoutButton {INPUT} at (186,0) size 72x72 - LayoutButton {INPUT} at (258,0) size 72x72 -layer at (171,157) size 0x72 transparent - LayoutSlider {INPUT} at (114,0) size 0x72 [color=#C4C4C4] - LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (171,190) size 18x6 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] - LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (171,190) size 18x6 scrollWidth 27 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (171,190) size 0x6 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (171,190) size 27x6 backgroundClip at (171,190) size 18x6 clip at (171,190) size 18x6 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] -layer at (57,229) size 240x36 - LayoutSlider {INPUT} at (0,144) size 240x36 [color=#C4C4C4] - LayoutFlexibleBox {DIV} at (24,0) size 192x6 -layer at (81,229) size 192x6 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 192x6 [bgcolor=#FFFFFF4D] -layer at (81,223) size 18x18 - LayoutBlockFlow (relative positioned) {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (81,229) size 192x6 scrollWidth 288 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 192x6 -layer at (81,229) size 0x6 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (81,229) size 288x6 backgroundClip at (81,229) size 192x6 clip at (81,229) size 192x6 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 288x6 [bgcolor=#FFFFFF8A] -layer at (57,310) size 240x180 - LayoutVideo {VIDEO} at (45,298) size 240x180 -layer at (43,291) size 268x218 - LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 - LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (43,291) size 268x218 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180 -layer at (43,291) size 268x218 clip at (43,291) size 240x180 - LayoutFlexibleBox {DIV} at (0,0) size 240x180 -layer at (104,306) size 153x153 clip at (104,306) size 132x132 - LayoutButton (positioned) {INPUT} at (54,6) size 132x132 - LayoutBlockFlow (anonymous) at (30,30) size 72x72 - LayoutBlockFlow {DIV} at (0,0) size 72x72 [bgcolor=#FFFFFFE6] -layer at (49,361) size 249x113 clip at (49,361) size 240x72 scrollWidth 330 - LayoutFlexibleBox (relative positioned) {DIV} at (0,72) size 240x72 - LayoutBlockFlow {DIV} at (24,6) size 42x66 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x24 - text run at (0,21) width 42: "0:00" - LayoutBlockFlow {DIV} at (72,-60) size 42x132 [color=#FFFFFF] - LayoutText {#text} at (0,21) size 42x90 - text run at (0,21) width 6: "/" - text run at (0,87) width 42: "0:06" - LayoutBlockFlow {DIV} at (114,72) size 0x0 - LayoutButton {INPUT} at (114,0) size 72x72 - LayoutButton {INPUT} at (186,0) size 72x72 - LayoutButton {INPUT} at (258,0) size 72x72 -layer at (162,381) size 12x71 transparent - LayoutSlider {INPUT} at (114,0) size 0x72 [color=#C4C4C4] - LayoutFlexibleBox {DIV} at (0,33) size 0x6 -layer at (167,414) size 19x9 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 18x6 [bgcolor=#FFFFFF4D] - LayoutBlockFlow {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (167,414) size 19x9 clip at (167,414) size 18x6 scrollWidth 27 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 18x6 -layer at (167,414) size 2x6 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (167,414) size 28x10 backgroundClip at (167,414) size 19x9 clip at (167,414) size 19x9 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 27x6 [bgcolor=#FFFFFF8A] -layer at (43,432) size 243x77 - LayoutSlider {INPUT} at (0,144) size 240x36 [color=#C4C4C4] - LayoutFlexibleBox {DIV} at (24,0) size 192x6 -layer at (72,437) size 190x39 - LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 192x6 [bgcolor=#FFFFFF4D] -layer at (71,431) size 21x20 - LayoutBlockFlow (relative positioned) {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF] -layer at (72,437) size 190x39 clip at (72,437) size 190x6 scrollWidth 288 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 192x6 -layer at (72,437) size 1x5 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF] -layer at (72,437) size 285x55 backgroundClip at (72,437) size 190x39 clip at (72,437) size 190x39 - LayoutBlockFlow (positioned) {DIV} at (0,0) size 288x6 [bgcolor=#FFFFFF8A]
diff --git a/third_party/WebKit/LayoutTests/virtual/autoupgrade-all-mixed-content/http/tests/mixed-autoupgrade/all/README.txt b/third_party/WebKit/LayoutTests/virtual/autoupgrade-all-mixed-content/http/tests/mixed-autoupgrade/all/README.txt new file mode 100644 index 0000000..a170d76 --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/autoupgrade-all-mixed-content/http/tests/mixed-autoupgrade/all/README.txt
@@ -0,0 +1 @@ +Tests that depend on the AutoupgradeMixedContent feature with the "mode" parameter set to "all". \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/virtual/autoupgrade-blockable-mixed-content/http/tests/mixed-autoupgrade/blockable/README.txt b/third_party/WebKit/LayoutTests/virtual/autoupgrade-blockable-mixed-content/http/tests/mixed-autoupgrade/blockable/README.txt new file mode 100644 index 0000000..4930315f --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/autoupgrade-blockable-mixed-content/http/tests/mixed-autoupgrade/blockable/README.txt
@@ -0,0 +1 @@ +Tests that depend on the AutoupgradeMixedContent feature with the "mode" parameter set to "blockable".
diff --git a/third_party/WebKit/LayoutTests/virtual/autoupgrade-optionally-blockable-mixed-content/http/tests/mixed-autoupgrade/optionally/README.txt b/third_party/WebKit/LayoutTests/virtual/autoupgrade-optionally-blockable-mixed-content/http/tests/mixed-autoupgrade/optionally/README.txt new file mode 100644 index 0000000..aeed7f2d --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/autoupgrade-optionally-blockable-mixed-content/http/tests/mixed-autoupgrade/optionally/README.txt
@@ -0,0 +1 @@ +Tests that depend on the AutoupgradeMixedContent feature with the "mode" parameter set to "optionally-blockable".
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h index 3d6721a..68e82b2 100644 --- a/third_party/blink/public/web/web_view.h +++ b/third_party/blink/public/web/web_view.h
@@ -88,7 +88,7 @@ using WebWidget::HandleInputEvent; using WebWidget::DispatchBufferedTouchEvents; using WebWidget::SetCursorVisibilityState; - using WebWidget::ApplyViewportDeltas; + using WebWidget::ApplyViewportChanges; using WebWidget::MouseCaptureLost; using WebWidget::SetFocus; using WebWidget::SelectionBounds;
diff --git a/third_party/blink/public/web/web_widget.h b/third_party/blink/public/web/web_widget.h index 900a584..916fd45d 100644 --- a/third_party/blink/public/web/web_widget.h +++ b/third_party/blink/public/web/web_widget.h
@@ -50,6 +50,10 @@ class SkBitmap; +namespace cc { +struct ApplyViewportChangesArgs; +} + namespace blink { class WebCoalescedInputEvent; @@ -164,11 +168,7 @@ // Applies viewport related properties during a commit from the compositor // thread. - virtual void ApplyViewportDeltas(const WebFloatSize& visual_viewport_delta, - const WebFloatSize& layout_viewport_delta, - const WebFloatSize& elastic_overscroll_delta, - float scale_factor, - float browser_controls_shown_ratio_delta) {} + virtual void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) {} virtual void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel, bool has_scrolled_by_touch) {}
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc index bb3dfcc..566b70c 100644 --- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc +++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -2043,8 +2043,8 @@ const ScrollSnapAlign& align, const ComputedStyle& style) { return CSSValuePair::Create( - CSSIdentifierValue::Create(align.alignment_inline), CSSIdentifierValue::Create(align.alignment_block), + CSSIdentifierValue::Create(align.alignment_inline), CSSValuePair::kDropIdenticalValues); }
diff --git a/third_party/blink/renderer/core/css/properties/longhands/scroll_snap_align_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/scroll_snap_align_custom.cc index 44cf3a57..8890163 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/scroll_snap_align_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/scroll_snap_align_custom.cc
@@ -16,20 +16,18 @@ CSSParserTokenRange& range, const CSSParserContext& context, const CSSParserLocalContext&) const { - CSSValueID x_id = range.Peek().Id(); - if (x_id != CSSValueNone && x_id != CSSValueStart && x_id != CSSValueEnd && - x_id != CSSValueCenter) + CSSValue* block_value = CSSPropertyParserHelpers::ConsumeIdent< + CSSValueNone, CSSValueStart, CSSValueEnd, CSSValueCenter>(range); + if (!block_value) return nullptr; - CSSValue* x_value = CSSPropertyParserHelpers::ConsumeIdent(range); if (range.AtEnd()) - return x_value; + return block_value; - CSSValueID y_id = range.Peek().Id(); - if (y_id != CSSValueNone && y_id != CSSValueStart && y_id != CSSValueEnd && - y_id != CSSValueCenter) - return x_value; - CSSValue* y_value = CSSPropertyParserHelpers::ConsumeIdent(range); - CSSValuePair* pair = CSSValuePair::Create(x_value, y_value, + CSSValue* inline_value = CSSPropertyParserHelpers::ConsumeIdent< + CSSValueNone, CSSValueStart, CSSValueEnd, CSSValueCenter>(range); + if (!inline_value) + return block_value; + CSSValuePair* pair = CSSValuePair::Create(block_value, inline_value, CSSValuePair::kDropIdenticalValues); return pair; }
diff --git a/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc b/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc index 7e641e35..abdd0ce 100644 --- a/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc +++ b/third_party/blink/renderer/core/events/web_input_event_conversion_test.cc
@@ -740,9 +740,9 @@ LocalFrameView* view = ToLocalFrame(web_view->GetPage()->MainFrame())->View(); - FloatSize elastic_overscroll(10, -20); - web_view->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), - elastic_overscroll, 1.0f, 0.0f); + gfx::Vector2dF elastic_overscroll(10, -20); + web_view->ApplyViewportChanges( + {gfx::Vector2dF(), elastic_overscroll, 1.0f, 0.0f}); // Just elastic overscroll. { @@ -757,11 +757,10 @@ IntPoint position = FlooredIntPoint(transformed_mouse_event.PositionInRootFrame()); - EXPECT_EQ(web_mouse_event.PositionInWidget().x + elastic_overscroll.Width(), + EXPECT_EQ(web_mouse_event.PositionInWidget().x + elastic_overscroll.x(), position.X()); - EXPECT_EQ( - web_mouse_event.PositionInWidget().y + elastic_overscroll.Height(), - position.Y()); + EXPECT_EQ(web_mouse_event.PositionInWidget().y + elastic_overscroll.y(), + position.Y()); EXPECT_EQ(web_mouse_event.PositionInScreen().x, transformed_mouse_event.PositionInScreen().x); EXPECT_EQ(web_mouse_event.PositionInScreen().y, @@ -788,10 +787,10 @@ FlooredIntPoint(transformed_mouse_event.PositionInRootFrame()); EXPECT_EQ(web_mouse_event.PositionInWidget().x / page_scale + - visual_offset.X() + elastic_overscroll.Width(), + visual_offset.X() + elastic_overscroll.x(), position.X()); EXPECT_EQ(web_mouse_event.PositionInWidget().y / page_scale + - visual_offset.Y() + elastic_overscroll.Height(), + visual_offset.Y() + elastic_overscroll.y(), position.Y()); EXPECT_EQ(web_mouse_event.PositionInScreen().x, transformed_mouse_event.PositionInScreen().x); @@ -814,9 +813,9 @@ web_view->Resize(WebSize(page_width, page_height)); web_view->UpdateAllLifecyclePhases(); - FloatSize elastic_overscroll(10, -20); - web_view->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), - elastic_overscroll, 1.0f, 0.0f); + gfx::Vector2dF elastic_overscroll(10, -20); + web_view->ApplyViewportChanges( + {gfx::Vector2dF(), elastic_overscroll, 1.0f, 0.0f}); FrameTestHelpers::ReloadFrame(web_view_helper.GetWebView()->MainFrameImpl()); LocalFrameView* view = ToLocalFrame(web_view->GetPage()->MainFrame())->View(); @@ -833,11 +832,10 @@ IntPoint position = FlooredIntPoint(transformed_mouse_event.PositionInRootFrame()); - EXPECT_EQ(web_mouse_event.PositionInWidget().x + elastic_overscroll.Width(), + EXPECT_EQ(web_mouse_event.PositionInWidget().x + elastic_overscroll.x(), position.X()); - EXPECT_EQ( - web_mouse_event.PositionInWidget().y + elastic_overscroll.Height(), - position.Y()); + EXPECT_EQ(web_mouse_event.PositionInWidget().y + elastic_overscroll.y(), + position.Y()); EXPECT_EQ(web_mouse_event.PositionInScreen().x, transformed_mouse_event.PositionInScreen().x); EXPECT_EQ(web_mouse_event.PositionInScreen().y,
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc index e9408193..09032f01 100644 --- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc +++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -449,8 +449,6 @@ web_frame_->Client()->DidStartProvisionalLoad( WebDocumentLoaderImpl::FromDocumentLoader(loader), wrapped_request); } - if (WebDevToolsAgentImpl* dev_tools = DevToolsAgent()) - dev_tools->DidStartProvisionalLoad(web_frame_->GetFrame()); virtual_time_pauser_.PauseVirtualTime(); } @@ -496,8 +494,6 @@ const ResourceError& error, WebHistoryCommitType commit_type) { web_frame_->DidFail(error, true, commit_type); - if (WebDevToolsAgentImpl* dev_tools = DevToolsAgent()) - dev_tools->DidFailProvisionalLoad(web_frame_->GetFrame()); virtual_time_pauser_.UnpauseVirtualTime(); }
diff --git a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc index 04eb8da..4509fbe 100644 --- a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc +++ b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
@@ -199,7 +199,7 @@ bool should_reattach = !reattach_session_state.is_null(); InspectorSession* inspector_session = new InspectorSession( - session_client, probe_sink_.Get(), 0, + session_client, probe_sink_.Get(), inspected_frames, 0, main_thread_debugger->GetV8Inspector(), main_thread_debugger->ContextGroupId(inspected_frames->Root()), std::move(reattach_session_state)); @@ -412,26 +412,6 @@ resource_content_loader_->DidCommitLoadForLocalFrame(frame); for (auto& session : sessions_) session->DidCommitLoadForLocalFrame(frame); - if (inspected_frames_->Root() == frame) { - for (auto& session : sessions_) - session->V8Session()->setSkipAllPauses(false); - } -} - -void WebDevToolsAgentImpl::DidFailProvisionalLoad(LocalFrame* frame) { - if (inspected_frames_->Root() == frame) { - for (auto& session : sessions_) - session->V8Session()->setSkipAllPauses(false); - } -} - -void WebDevToolsAgentImpl::DidStartProvisionalLoad(LocalFrame* frame) { - if (inspected_frames_->Root() == frame) { - for (auto& session : sessions_) { - session->V8Session()->setSkipAllPauses(true); - session->V8Session()->resume(); - } - } } bool WebDevToolsAgentImpl::ScreencastEnabled() {
diff --git a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h index 4262f26..f9a84dd 100644 --- a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h +++ b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
@@ -83,8 +83,6 @@ // Instrumentation from web/ layer. void DidCommitLoadForLocalFrame(LocalFrame*); - void DidFailProvisionalLoad(LocalFrame*); - void DidStartProvisionalLoad(LocalFrame*); bool ScreencastEnabled(); String NavigationInitiatorInfo(LocalFrame*); String EvaluateInOverlayForTesting(const String& script);
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc index c178723..f968f22 100644 --- a/third_party/blink/renderer/core/exported/web_frame_test.cc +++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -3433,8 +3433,8 @@ float scale_delta = web_view_impl->FakePageScaleAnimationPageScaleForTesting() / web_view_impl->PageScaleFactor(); - web_view_impl->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), - WebFloatSize(), scale_delta, 0); + web_view_impl->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), scale_delta, 0}); scale = web_view_impl->PageScaleFactor(); } @@ -3623,8 +3623,8 @@ // back to the div. SimulateDoubleTap(web_view_helper.GetWebView(), top_point, scale); EXPECT_FLOAT_EQ(1, scale); - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 0.6f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 0.6f, 0}); SimulateDoubleTap(web_view_helper.GetWebView(), bottom_point, scale); EXPECT_FLOAT_EQ(1, scale); SimulateDoubleTap(web_view_helper.GetWebView(), bottom_point, scale); @@ -3633,8 +3633,8 @@ // If we didn't yet get an auto-zoom update and a second double-tap arrives, // should go back to minimum scale. - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.1f, 0}); web_view_helper.GetWebView()->AnimateDoubleTapZoom(top_point); EXPECT_TRUE( web_view_helper.GetWebView()->FakeDoubleTapAnimationPendingForTesting()); @@ -3684,8 +3684,8 @@ EXPECT_FLOAT_EQ(1, scale); // Zoom in to reset double_tap_zoom_in_effect flag. - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.1f, 0}); // 1 < minimumPageScale < doubleTapZoomAlreadyLegibleScale web_view_helper.GetWebView()->SetDefaultPageScaleLimits(1.1f, 4); web_view_helper.GetWebView()->UpdateAllLifecyclePhases(); @@ -3705,8 +3705,8 @@ EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale); // Zoom in to reset double_tap_zoom_in_effect flag. - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.1f, 0}); // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.95f, 4); web_view_helper.GetWebView()->UpdateAllLifecyclePhases(); @@ -3774,8 +3774,8 @@ EXPECT_FLOAT_EQ(legible_scale, scale); // Zoom in to reset double_tap_zoom_in_effect flag. - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.1f, 0}); // 1 < maximumLegibleScaleFactor < minimumPageScale < // doubleTapZoomAlreadyLegibleScale web_view_helper.GetWebView()->SetDefaultPageScaleLimits(1.0f, 4); @@ -3796,8 +3796,8 @@ EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale); // Zoom in to reset double_tap_zoom_in_effect flag. - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.1f, 0}); // minimumPageScale < 1 < maximumLegibleScaleFactor < // doubleTapZoomAlreadyLegibleScale web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.95f, 4); @@ -3818,8 +3818,8 @@ EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale); // Zoom in to reset double_tap_zoom_in_effect flag. - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.1f, 0}); // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale < // maximumLegibleScaleFactor web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.9f, 4); @@ -3891,8 +3891,8 @@ EXPECT_FLOAT_EQ(legible_scale, scale); // Zoom in to reset double_tap_zoom_in_effect flag. - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.1f, 0}); // 1 < accessibilityFontScaleFactor < minimumPageScale < // doubleTapZoomAlreadyLegibleScale web_view_helper.GetWebView()->SetDefaultPageScaleLimits(1.0f, 4); @@ -3913,8 +3913,8 @@ EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale); // Zoom in to reset double_tap_zoom_in_effect flag. - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.1f, 0}); // minimumPageScale < 1 < accessibilityFontScaleFactor < // doubleTapZoomAlreadyLegibleScale web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.95f, 4); @@ -3935,8 +3935,8 @@ EXPECT_FLOAT_EQ(double_tap_zoom_already_legible_scale, scale); // Zoom in to reset double_tap_zoom_in_effect flag. - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.1f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.1f, 0}); // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale < // accessibilityFontScaleFactor web_view_helper.GetWebView()->SetDefaultPageScaleLimits(0.9f, 4); @@ -7246,8 +7246,8 @@ // Do a compositor scroll, verify that this is counted as a user scroll. scrollable_area->DidScroll(FloatPoint(0, 1)); - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.7f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.7f, 0}); EXPECT_TRUE(client.WasFrameScrolled()); EXPECT_TRUE(initial_scroll_state.was_scrolled_by_user); @@ -7256,8 +7256,8 @@ // The page scale 1.0f and scroll. scrollable_area->DidScroll(FloatPoint(0, 2)); - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.0f, 0}); EXPECT_TRUE(client.WasFrameScrolled()); EXPECT_TRUE(initial_scroll_state.was_scrolled_by_user); client.Reset(); @@ -7265,16 +7265,16 @@ // No scroll event if there is no scroll delta. scrollable_area->DidScroll(FloatPoint(0, 2)); - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 1.0f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1.0f, 0}); EXPECT_FALSE(client.WasFrameScrolled()); EXPECT_FALSE(initial_scroll_state.was_scrolled_by_user); client.Reset(); // Non zero page scale and scroll. scrollable_area->DidScroll(FloatPoint(9, 15)); - web_view_helper.GetWebView()->ApplyViewportDeltas( - WebFloatSize(), WebFloatSize(), WebFloatSize(), 0.6f, 0); + web_view_helper.GetWebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 0.6f, 0}); EXPECT_TRUE(client.WasFrameScrolled()); EXPECT_TRUE(initial_scroll_state.was_scrolled_by_user); client.Reset(); @@ -8088,44 +8088,44 @@ // Simulate the browser controls showing by 20px, thus shrinking the viewport // and allowing it to scroll an additional 20px. - web_view->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1.0f, 20.0f / browser_controls_height); + web_view->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1.0f, + 20.0f / browser_controls_height}); EXPECT_EQ(ScrollOffset(0, 1920), frame_view->LayoutViewport()->MaximumScrollOffset()); // Show more, make sure the scroll actually gets clamped. - web_view->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1.0f, 20.0f / browser_controls_height); + web_view->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1.0f, + 20.0f / browser_controls_height}); web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 2000)); EXPECT_EQ(ScrollOffset(0, 1940), frame_view->LayoutViewport()->GetScrollOffset()); // Hide until there's 10px showing. - web_view->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1.0f, -30.0f / browser_controls_height); + web_view->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1.0f, + -30.0f / browser_controls_height}); EXPECT_EQ(ScrollOffset(0, 1910), frame_view->LayoutViewport()->MaximumScrollOffset()); // Simulate a LayoutEmbeddedContent::resize. The frame is resized to // accomodate the browser controls and Blink's view of the browser controls // matches that of the CC - web_view->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1.0f, 30.0f / browser_controls_height); + web_view->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1.0f, + 30.0f / browser_controls_height}); web_view->ResizeWithBrowserControls(WebSize(100, 60), 40.0f, 0, true); web_view->UpdateAllLifecyclePhases(); EXPECT_EQ(ScrollOffset(0, 1940), frame_view->LayoutViewport()->MaximumScrollOffset()); // Now simulate hiding. - web_view->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1.0f, -10.0f / browser_controls_height); + web_view->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1.0f, + -10.0f / browser_controls_height}); EXPECT_EQ(ScrollOffset(0, 1930), frame_view->LayoutViewport()->MaximumScrollOffset()); // Reset to original state: 100px widget height, browser controls fully // hidden. - web_view->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1.0f, -30.0f / browser_controls_height); + web_view->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1.0f, + -30.0f / browser_controls_height}); web_view->ResizeWithBrowserControls(WebSize(100, 100), browser_controls_height, 0, false); web_view->UpdateAllLifecyclePhases(); @@ -8136,13 +8136,13 @@ // should allow an extra 0.5px of scrolling in the visual viewport. Make // sure we're not losing any pixels when applying the adjustment on the // main frame. - web_view->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1.0f, 1.0f / browser_controls_height); + web_view->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1.0f, + 1.0f / browser_controls_height}); EXPECT_EQ(ScrollOffset(0, 1901), frame_view->LayoutViewport()->MaximumScrollOffset()); - web_view->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1.0f, 2.0f / browser_controls_height); + web_view->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1.0f, + 2.0f / browser_controls_height}); EXPECT_EQ(ScrollOffset(0, 1903), frame_view->LayoutViewport()->MaximumScrollOffset()); }
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 865f79d..81b10a7 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3286,14 +3286,7 @@ scoped_defer_commits_ = layer_tree_view_->DeferCommits(); } -void WebViewImpl::ApplyViewportDeltas( - const WebFloatSize& visual_viewport_delta, - // TODO(bokan): This parameter is to be removed but requires adjusting many - // callsites. - const WebFloatSize&, - const WebFloatSize& elastic_overscroll_delta, - float page_scale_delta, - float browser_controls_shown_ratio_delta) { +void WebViewImpl::ApplyViewportChanges(const ApplyViewportChangesArgs& args) { VisualViewport& visual_viewport = GetPage()->GetVisualViewport(); // Store the desired offsets the visual viewport before setting the top @@ -3301,21 +3294,21 @@ // viewports to keep the offsets valid. The compositor may have already // done that so we don't want to double apply the deltas here. FloatPoint visual_viewport_offset = visual_viewport.VisibleRect().Location(); - visual_viewport_offset.Move(visual_viewport_delta.width, - visual_viewport_delta.height); + visual_viewport_offset.Move(args.inner_delta.x(), args.inner_delta.y()); GetBrowserControls().SetShownRatio(GetBrowserControls().ShownRatio() + - browser_controls_shown_ratio_delta); + args.browser_controls_delta); - SetPageScaleFactorAndLocation(PageScaleFactor() * page_scale_delta, + SetPageScaleFactorAndLocation(PageScaleFactor() * args.page_scale_delta, visual_viewport_offset); - if (page_scale_delta != 1) { + if (args.page_scale_delta != 1) { double_tap_zoom_pending_ = false; visual_viewport.UserDidChangeScale(); } - elastic_overscroll_ += elastic_overscroll_delta; + elastic_overscroll_ += FloatSize(args.elastic_overscroll_delta.x(), + args.elastic_overscroll_delta.y()); } void WebViewImpl::RecordWheelAndTouchScrollingCount(
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 db5e6b3..fb8a36b 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.h +++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -58,6 +58,7 @@ #include "third_party/blink/renderer/core/page/scoped_page_pauser.h" #include "third_party/blink/renderer/platform/geometry/int_point.h" #include "third_party/blink/renderer/platform/geometry/int_rect.h" +#include "third_party/blink/renderer/platform/graphics/apply_viewport_changes.h" #include "third_party/blink/renderer/platform/graphics/graphics_layer.h" #include "third_party/blink/renderer/platform/graphics/touch_action.h" #include "third_party/blink/renderer/platform/heap/member.h" @@ -129,11 +130,7 @@ WebInputEventResult HandleInputEvent(const WebCoalescedInputEvent&) override; WebInputEventResult DispatchBufferedTouchEvents() override; void SetCursorVisibilityState(bool is_visible) override; - void ApplyViewportDeltas(const WebFloatSize& visual_viewport_delta, - const WebFloatSize& layout_viewport_delta, - const WebFloatSize& elastic_overscroll_delta, - float page_scale_delta, - float browser_controls_shown_ratio_delta) override; + void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override; void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel, bool has_scrolled_by_touch) override; void MouseCaptureLost() override;
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.cc b/third_party/blink/renderer/core/frame/visual_viewport.cc index 39f9cb41..f72f6fec 100644 --- a/third_party/blink/renderer/core/frame/visual_viewport.cc +++ b/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -253,10 +253,6 @@ ScrollableArea::Trace(visitor); } -void VisualViewport::SetNeedsPaintPropertiesUpdate() { - needs_paint_property_update_ = true; -} - void VisualViewport::UpdateStyleAndLayoutIgnorePendingStylesheets() const { if (!MainFrame()) return;
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.h b/third_party/blink/renderer/core/frame/visual_viewport.h index 071c04b..4fe803da 100644 --- a/third_party/blink/renderer/core/frame/visual_viewport.h +++ b/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -269,7 +269,8 @@ CompositorElementId GetCompositorOverscrollElasticityElementId() const; - void SetNeedsPaintPropertiesUpdate(); + void SetNeedsPaintPropertyUpdate() { needs_paint_property_update_ = true; } + bool NeedsPaintPropertyUpdate() const { return needs_paint_property_update_; } private: explicit VisualViewport(Page&);
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 51b9a7b..93621f8 100644 --- a/third_party/blink/renderer/core/frame/visual_viewport_test.cc +++ b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
@@ -49,6 +49,7 @@ #include "third_party/blink/renderer/platform/geometry/double_rect.h" #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h" #include "third_party/blink/renderer/platform/graphics/graphics_layer.h" +#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h" #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "third_party/blink/renderer/platform/testing/url_test_helpers.h" @@ -311,6 +312,20 @@ EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 100), visual_viewport.VisibleRect().Size()); + // Verify the paint property nodes and GeometryMapper cache. + if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() || + RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) { + WebView()->UpdateAllLifecyclePhases(); + EXPECT_EQ(TransformationMatrix().Scale(2), + visual_viewport.GetPageScaleNode()->Matrix()); + EXPECT_EQ(TransformationMatrix().Translate(0, -300), + visual_viewport.GetScrollTranslationNode()->Matrix()); + EXPECT_EQ(TransformationMatrix().Scale(2).Translate(0, -300), + GeometryMapper::SourceToDestinationProjection( + visual_viewport.GetScrollTranslationNode(), + &TransformPaintPropertyNode::Root())); + } + // Perform the resizing WebView()->Resize(IntSize(200, 100)); @@ -320,6 +335,20 @@ EXPECT_EQ(ScrollOffset(0, 625), GetFrame()->View()->LayoutViewport()->GetScrollOffset()); EXPECT_FLOAT_SIZE_EQ(FloatSize(0, 75), visual_viewport.GetScrollOffset()); + + // Verify the paint property nodes and GeometryMapper cache. + if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() || + RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) { + WebView()->UpdateAllLifecyclePhases(); + EXPECT_EQ(TransformationMatrix().Scale(4), + visual_viewport.GetPageScaleNode()->Matrix()); + EXPECT_EQ(TransformationMatrix().Translate(0, -75), + visual_viewport.GetScrollTranslationNode()->Matrix()); + EXPECT_EQ(TransformationMatrix().Scale(4).Translate(0, -75), + GeometryMapper::SourceToDestinationProjection( + visual_viewport.GetScrollTranslationNode(), + &TransformPaintPropertyNode::Root())); + } } // Test that the VisualViewport works as expected in case if a scaled @@ -371,6 +400,20 @@ EXPECT_FLOAT_SIZE_EQ(FloatSize(50, 100), visual_viewport.VisibleRect().Size()); + // Verify the paint property nodes and GeometryMapper cache. + if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() || + RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) { + WebView()->UpdateAllLifecyclePhases(); + EXPECT_EQ(TransformationMatrix().Scale(2), + visual_viewport.GetPageScaleNode()->Matrix()); + EXPECT_EQ(TransformationMatrix().Translate(-150, 0), + visual_viewport.GetScrollTranslationNode()->Matrix()); + EXPECT_EQ(TransformationMatrix().Scale(2).Translate(-150, 0), + GeometryMapper::SourceToDestinationProjection( + visual_viewport.GetScrollTranslationNode(), + &TransformPaintPropertyNode::Root())); + } + WebView()->Resize(IntSize(200, 100)); // After resizing the scale changes 2.0 -> 4.0 @@ -379,6 +422,20 @@ EXPECT_EQ(ScrollOffset(0, 0), GetFrame()->View()->LayoutViewport()->GetScrollOffset()); EXPECT_FLOAT_SIZE_EQ(FloatSize(150, 0), visual_viewport.GetScrollOffset()); + + // Verify the paint property nodes and GeometryMapper cache. + if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() || + RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) { + WebView()->UpdateAllLifecyclePhases(); + EXPECT_EQ(TransformationMatrix().Scale(4), + visual_viewport.GetPageScaleNode()->Matrix()); + EXPECT_EQ(TransformationMatrix().Translate(-150, 0), + visual_viewport.GetScrollTranslationNode()->Matrix()); + EXPECT_EQ(TransformationMatrix().Scale(4).Translate(-150, 0), + GeometryMapper::SourceToDestinationProjection( + visual_viewport.GetScrollTranslationNode(), + &TransformPaintPropertyNode::Root())); + } } // Test that the container layer gets sized properly if the WebView is resized @@ -1214,8 +1271,7 @@ EXPECT_EQ(IntSize(1000, 900), frame_view.FrameRect().Size()); // Simulate bringing down the browser controls by 20px. - WebView()->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1, 1); + WebView()->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1, 1}); EXPECT_EQ(FloatSize(500, 430), visual_viewport.VisibleRect().Size()); // Test that the scroll bounds are adjusted appropriately: the visual viewport @@ -1232,8 +1288,8 @@ frame_view.LayoutViewport()->GetScrollOffset()); // Simulate bringing up the browser controls by 10.5px. - WebView()->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1, -10.5f / 20); + WebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1, -10.5f / 20}); EXPECT_FLOAT_SIZE_EQ(FloatSize(500, 440.5f), visual_viewport.VisibleRect().Size()); @@ -1267,8 +1323,7 @@ // Simulate bringing down the browser controls by 20px. Since we're zoomed in, // the browser controls take up half as much space (in document-space) than // they do at an unzoomed level. - WebView()->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1, 1); + WebView()->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1, 1}); EXPECT_EQ(FloatSize(250, 215), visual_viewport.VisibleRect().Size()); // Test that the scroll bounds are adjusted appropriately. @@ -1284,8 +1339,8 @@ // Scale back out, LocalFrameView max scroll shouldn't have changed. Visual // viewport should be moved up to accomodate larger view. - WebView()->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 0.5f, 0); + WebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 0.5f, 0}); EXPECT_EQ(1, visual_viewport.Scale()); EXPECT_EQ(expected, frame_view.LayoutViewport()->GetScrollOffset()); frame_view.LayoutViewport()->ScrollBy(ScrollOffset(10000, 10000), @@ -1297,13 +1352,13 @@ EXPECT_EQ(FloatSize(500, 860 - 430), visual_viewport.GetScrollOffset()); // Scale out, use a scale that causes fractional rects. - WebView()->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 0.8f, -1); + WebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 0.8f, -1}); EXPECT_EQ(FloatSize(625, 562.5), visual_viewport.VisibleRect().Size()); // Bring out the browser controls by 11 - WebView()->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1, 11 / 20.f); + WebView()->ApplyViewportChanges( + {gfx::Vector2dF(), gfx::Vector2dF(), 1, 11 / 20.f}); EXPECT_EQ(FloatSize(625, 548.75), visual_viewport.VisibleRect().Size()); // Ensure max scroll offsets are updated properly. @@ -1469,8 +1524,7 @@ TEST_P(VisualViewportTest, TestTopControlHidingResizeDoesntClampMainFrame) { InitializeWithAndroidSettings(); WebView()->ResizeWithBrowserControls(WebView()->Size(), 500, 0, false); - WebView()->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1, 1); + WebView()->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1, 1}); WebView()->ResizeWithBrowserControls(WebSize(1000, 1000), 500, 0, true); RegisterMockedHttpURLLoad("content-width-1000.html"); @@ -1480,8 +1534,7 @@ // Scroll the LocalFrameView to the bottom of the page but "hide" the browser // controls on the compositor side so the max scroll position should account // for the full viewport height. - WebView()->ApplyViewportDeltas(WebFloatSize(), WebFloatSize(), WebFloatSize(), - 1, -1); + WebView()->ApplyViewportChanges({gfx::Vector2dF(), gfx::Vector2dF(), 1, -1}); LocalFrameView& frame_view = *WebView()->MainFrameImpl()->GetFrameView(); frame_view.LayoutViewport()->SetScrollOffset(ScrollOffset(0, 10000), kProgrammaticScroll); @@ -1755,8 +1808,8 @@ VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport(); // Apply some scroll and scale from the impl-side. - WebView()->ApplyViewportDeltas(WebFloatSize(300, 200), WebFloatSize(0, 0), - WebFloatSize(0, 0), 2, 0); + WebView()->ApplyViewportChanges( + {gfx::Vector2dF(300, 200), gfx::Vector2dF(0, 0), 2, 0}); EXPECT_EQ(FloatSize(300, 200), visual_viewport.GetScrollOffset()); @@ -2386,8 +2439,8 @@ visual_viewport.GetScrollNode()->ContentsSize()); } - WebView().ApplyViewportDeltas(WebFloatSize(1, 1), WebFloatSize(), - WebFloatSize(), 2, 1); + WebView().ApplyViewportChanges( + {gfx::Vector2dF(1, 1), gfx::Vector2dF(), 2, 1}); EXPECT_EQ(gfx::Size(400, 600), visual_viewport.ContainerLayer()->Size()); EXPECT_EQ(gfx::Size(400, 600), visual_viewport.ContainerLayer()->CcLayer()->bounds());
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index 3c2210de..c37c6a6b 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -599,13 +599,7 @@ return mutator_dispatcher_; } -void WebFrameWidgetImpl::ApplyViewportDeltas( - const WebFloatSize& visual_viewport_delta, - const WebFloatSize& main_frame_delta, - const WebFloatSize& elastic_overscroll_delta, - float page_scale_delta, - float browser_controls_delta) { - // FIXME: To be implemented. +void WebFrameWidgetImpl::ApplyViewportChanges(const ApplyViewportChangesArgs&) { } void WebFrameWidgetImpl::MouseCaptureLost() {
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h index ab70553..e1979d2 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -43,6 +43,7 @@ #include "third_party/blink/renderer/core/frame/web_frame_widget_base.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" #include "third_party/blink/renderer/core/page/page_widget_delegate.h" +#include "third_party/blink/renderer/platform/graphics/apply_viewport_changes.h" #include "third_party/blink/renderer/platform/graphics/graphics_layer.h" #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/heap/self_keep_alive.h" @@ -94,11 +95,7 @@ WebInputEventResult HandleInputEvent(const WebCoalescedInputEvent&) override; void SetCursorVisibilityState(bool is_visible) override; - void ApplyViewportDeltas(const WebFloatSize& visual_viewport_delta, - const WebFloatSize& main_frame_delta, - const WebFloatSize& elastic_overscroll_delta, - float page_scale_delta, - float browser_controls_delta) override; + void ApplyViewportChanges(const ApplyViewportChangesArgs&) override; void MouseCaptureLost() override; void SetFocus(bool enable) override; SkColor BackgroundColor() const override;
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc index 0d106f0a..c56d7946 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
@@ -102,15 +102,9 @@ web_view_->SetCursorVisibilityState(is_visible); } -void WebViewFrameWidget::ApplyViewportDeltas( - const WebFloatSize& visual_viewport_delta, - const WebFloatSize& layout_viewport_delta, - const WebFloatSize& elastic_overscroll_delta, - float scale_factor, - float browser_controls_shown_ratio_delta) { - web_view_->ApplyViewportDeltas(visual_viewport_delta, layout_viewport_delta, - elastic_overscroll_delta, scale_factor, - browser_controls_shown_ratio_delta); +void WebViewFrameWidget::ApplyViewportChanges( + const ApplyViewportChangesArgs& args) { + web_view_->ApplyViewportChanges(args); } void WebViewFrameWidget::RecordWheelAndTouchScrollingCount(
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.h b/third_party/blink/renderer/core/frame/web_view_frame_widget.h index 0ed4e90..044004cd 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.h +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.h
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/frame/web_frame_widget_base.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/platform/graphics/apply_viewport_changes.h" #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/heap/self_keep_alive.h" @@ -58,11 +59,7 @@ WebInputEventResult HandleInputEvent(const WebCoalescedInputEvent&) override; WebInputEventResult DispatchBufferedTouchEvents() override; void SetCursorVisibilityState(bool is_visible) override; - void ApplyViewportDeltas(const WebFloatSize& visual_viewport_delta, - const WebFloatSize& layout_viewport_delta, - const WebFloatSize& elastic_overscroll_delta, - float scale_factor, - float browser_controls_shown_ratio_delta) override; + void ApplyViewportChanges(const ApplyViewportChangesArgs&) override; void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel, bool has_scrolled_by_touch) override; void MouseCaptureLost() override;
diff --git a/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/third_party/blink/renderer/core/fullscreen/fullscreen.cc index 1c58d04..791a834 100644 --- a/third_party/blink/renderer/core/fullscreen/fullscreen.cc +++ b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
@@ -116,7 +116,7 @@ // Update paint properties on the visual viewport since // user-input-scrollable bits will change based on fullscreen state. if (Page* page = frame->GetPage()) - page->GetVisualViewport().SetNeedsPaintPropertiesUpdate(); + page->GetVisualViewport().SetNeedsPaintPropertyUpdate(); } }
diff --git a/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc b/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc index e6d9575..5289eb4f 100644 --- a/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc +++ b/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
@@ -587,7 +587,6 @@ } } style->SetWidth(Length(ceilf(width), kFixed)); - style->SetUnique(); return style; }
diff --git a/third_party/blink/renderer/core/html/forms/html_option_element.cc b/third_party/blink/renderer/core/html/forms/html_option_element.cc index d1c3e09..4f88654 100644 --- a/third_party/blink/renderer/core/html/forms/html_option_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_option_element.cc
@@ -268,12 +268,12 @@ } void HTMLOptionElement::ChildrenChanged(const ChildrenChange& change) { + HTMLElement::ChildrenChanged(change); if (HTMLDataListElement* data_list = OwnerDataListElement()) data_list->OptionElementChildrenChanged(); else if (HTMLSelectElement* select = OwnerSelectElement()) select->OptionElementChildrenChanged(*this); UpdateLabel(); - HTMLElement::ChildrenChanged(change); } HTMLDataListElement* HTMLOptionElement::OwnerDataListElement() const {
diff --git a/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc b/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc index fa68adc9..30b5ac5f 100644 --- a/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc +++ b/third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc
@@ -351,7 +351,6 @@ scoped_refptr<ComputedStyle> style = ComputedStyle::Clone(*original_style); style->SetDirection(content_direction); style->SetDisplay(new_display); - style->SetUnique(); return style; }
diff --git a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc index 0bbcdc9..c07c17f 100644 --- a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc +++ b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
@@ -88,7 +88,6 @@ // We don't want the shadow dom to be editable, so we set this block to // read-only in case the input itself is editable. style->SetUserModify(EUserModify::kReadOnly); - style->SetUnique(); return style; } @@ -169,7 +168,6 @@ ? EUserModify::kReadOnly : EUserModify::kReadWritePlaintextOnly); text_block_style->SetDisplay(EDisplay::kBlock); - text_block_style->SetUnique(); if (!IsHTMLTextAreaElement(host)) { text_block_style->SetWhiteSpace(EWhiteSpace::kPre);
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl index 74401a0..b63737e1 100644 --- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl +++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -1800,7 +1800,10 @@ parameters Page.FrameId frameId returns - NodeId nodeId + # Resulting node. + BackendNodeId backendNodeId + # Id of the node at given coordinates, only when enabled. + optional NodeId nodeId # Fired when `Element`'s attribute is modified. event attributeModified
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc index d2c508e3..2fe328d 100644 --- a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
@@ -2231,8 +2231,10 @@ return Response::OK(); } -protocol::Response InspectorDOMAgent::getFrameOwner(const String& frame_id, - int* node_id) { +protocol::Response InspectorDOMAgent::getFrameOwner( + const String& frame_id, + int* backend_node_id, + protocol::Maybe<int>* node_id) { Frame* frame = inspected_frames_->Root(); for (; frame; frame = frame->Tree().TraverseNext(inspected_frames_->Root())) { if (IdentifiersFactory::FrameId(frame) == frame_id) @@ -2243,8 +2245,14 @@ HTMLFrameOwnerElement* frame_owner = ToHTMLFrameOwnerElement(frame->Owner()); if (!frame_owner) return Response::Error("No iframe owner for given node"); - *node_id = - PushNodePathToFrontend(frame_owner, document_node_to_id_map_.Get()); + + *backend_node_id = DOMNodeIds::IdForNode(frame_owner); + if (enabled_.Get()) { + Response response = PushDocumentUponHandlelessOperation(); + if (!response.isSuccess()) + return response; + *node_id = PushNodePathToFrontend(frame_owner); + } return Response::OK(); }
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_agent.h b/third_party/blink/renderer/core/inspector/inspector_dom_agent.h index f9da144..7042f4ec 100644 --- a/third_party/blink/renderer/core/inspector/inspector_dom_agent.h +++ b/third_party/blink/renderer/core/inspector/inspector_dom_agent.h
@@ -213,7 +213,8 @@ std::unique_ptr<protocol::DOM::Node>*) override; protocol::Response getFrameOwner(const String& frame_id, - int* node_id) override; + int* backend_node_id, + protocol::Maybe<int>* node_id) override; bool Enabled() const; void ReleaseDanglingNodes();
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc index 9ce99e5..94fbd74 100644 --- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -581,7 +581,7 @@ protocol = response.GetResourceLoadInfo()->npn_negotiated_protocol; if (protocol.IsEmpty() || protocol == "unknown") { if (response.WasFetchedViaSPDY()) { - protocol = "spdy"; + protocol = "h2"; } else if (response.IsHTTP()) { protocol = "http"; if (response.HttpVersion() ==
diff --git a/third_party/blink/renderer/core/inspector/inspector_session.cc b/third_party/blink/renderer/core/inspector/inspector_session.cc index 0b997958..b13a610 100644 --- a/third_party/blink/renderer/core/inspector/inspector_session.cc +++ b/third_party/blink/renderer/core/inspector/inspector_session.cc
@@ -7,6 +7,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_controller.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/use_counter.h" +#include "third_party/blink/renderer/core/inspector/inspected_frames.h" #include "third_party/blink/renderer/core/inspector/inspector_base_agent.h" #include "third_party/blink/renderer/core/inspector/inspector_session_state.h" #include "third_party/blink/renderer/core/inspector/protocol/Protocol.h" @@ -35,6 +36,7 @@ InspectorSession::InspectorSession( Client* client, CoreProbeSink* instrumenting_agents, + InspectedFrames* inspected_frames, int session_id, v8_inspector::V8Inspector* inspector, int context_group_id, @@ -44,6 +46,7 @@ session_id_(session_id), disposed_(false), instrumenting_agents_(instrumenting_agents), + inspected_frames_(inspected_frames), inspector_backend_dispatcher_(new protocol::UberDispatcher(this)), session_state_(std::move(reattach_session_state)), v8_session_state_(kV8StateKey), @@ -56,6 +59,8 @@ v8_session_ = inspector->connect(context_group_id, /*channel*/ this, ToV8InspectorStringView(v8_session_state_json_.Get())); + + instrumenting_agents_->addInspectorSession(this); } InspectorSession::~InspectorSession() { @@ -77,6 +82,7 @@ void InspectorSession::Dispose() { DCHECK(!disposed_); disposed_ = true; + instrumenting_agents_->removeInspectorSession(this); inspector_backend_dispatcher_.reset(); for (wtf_size_t i = agents_.size(); i > 0; i--) agents_[i - 1]->Dispose(); @@ -116,9 +122,23 @@ } } +void InspectorSession::DidStartProvisionalLoad(LocalFrame* frame) { + if (inspected_frames_->Root() == frame) { + v8_session_->setSkipAllPauses(true); + v8_session_->resume(); + } +} + +void InspectorSession::DidFailProvisionalLoad(LocalFrame* frame) { + if (inspected_frames_->Root() == frame) + v8_session_->setSkipAllPauses(false); +} + void InspectorSession::DidCommitLoadForLocalFrame(LocalFrame* frame) { for (wtf_size_t i = 0; i < agents_.size(); i++) agents_[i]->DidCommitLoadForLocalFrame(frame); + if (inspected_frames_->Root() == frame) + v8_session_->setSkipAllPauses(false); } void InspectorSession::sendProtocolResponse( @@ -227,6 +247,7 @@ void InspectorSession::Trace(blink::Visitor* visitor) { visitor->Trace(instrumenting_agents_); + visitor->Trace(inspected_frames_); visitor->Trace(agents_); }
diff --git a/third_party/blink/renderer/core/inspector/inspector_session.h b/third_party/blink/renderer/core/inspector/inspector_session.h index 8474140..fc3e45dce 100644 --- a/third_party/blink/renderer/core/inspector/inspector_session.h +++ b/third_party/blink/renderer/core/inspector/inspector_session.h
@@ -19,6 +19,7 @@ namespace blink { class InspectorAgent; +class InspectedFrames; class CoreProbeSink; class LocalFrame; @@ -44,6 +45,7 @@ InspectorSession( Client*, CoreProbeSink*, + InspectedFrames*, int session_id, v8_inspector::V8Inspector*, int context_group_id, @@ -57,6 +59,8 @@ void Append(InspectorAgent*); void Restore(); void Dispose(); + void DidStartProvisionalLoad(LocalFrame*); + void DidFailProvisionalLoad(LocalFrame*); void DidCommitLoadForLocalFrame(LocalFrame*); void DispatchProtocolMessage(int call_id, const String& method, @@ -93,6 +97,7 @@ int session_id_; bool disposed_; Member<CoreProbeSink> instrumenting_agents_; + Member<InspectedFrames> inspected_frames_; std::unique_ptr<protocol::UberDispatcher> inspector_backend_dispatcher_; InspectorSessionState session_state_; HeapVector<Member<InspectorAgent>> agents_;
diff --git a/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc b/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc index a447ee2..83e69621 100644 --- a/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc +++ b/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
@@ -83,13 +83,13 @@ if (sessions_.find(session_id) != sessions_.end()) return; + InspectedFrames* inspected_frames = new InspectedFrames(nullptr); InspectorSession* session = new InspectorSession( - this, probe_sink_.Get(), session_id, debugger_->GetV8Inspector(), - debugger_->ContextGroupId(thread_), nullptr); + this, probe_sink_.Get(), inspected_frames, session_id, + debugger_->GetV8Inspector(), debugger_->ContextGroupId(thread_), nullptr); session->Append(new InspectorLogAgent(thread_->GetConsoleMessageStorage(), nullptr, session->V8Session())); if (thread_->GlobalScope()->IsWorkerGlobalScope()) { - InspectedFrames* inspected_frames = new InspectedFrames(nullptr); WorkerGlobalScope* worker_global_scope = ToWorkerGlobalScope(thread_->GlobalScope()); DCHECK(worker_global_scope->EnsureFetcher());
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc index 1c8a55b..da61f2c 100644 --- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc +++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -359,15 +359,10 @@ } FlexLayoutAlgorithm::FlexLayoutAlgorithm(const ComputedStyle* style, - LayoutUnit line_break_length, - FlexItemVector& all_items) + LayoutUnit line_break_length) : style_(style), line_break_length_(line_break_length), - all_items_(all_items), - next_item_index_(0) { - for (FlexItem& item : all_items_) - item.algorithm = this; -} + next_item_index_(0) {} FlexLine* FlexLayoutAlgorithm::ComputeNextFlexLine( LayoutUnit container_logical_width) {
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h index d6a6b40..bae8b0f 100644 --- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h +++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -243,12 +243,11 @@ // https://drafts.csswg.org/css-flexbox/ // // Expected usage is as follows: -// FlexItemVector flex_items; -// for (each child) { -// flex_items.emplace_back(...caller must compute these values...) +// FlexLayoutAlgorithm algorithm(Style(), MainAxisLength(), flex_items); +// for (each child) { +// algorithm.emplace_back(...caller must compute these values...) // } // LayoutUnit cross_axis_offset = border + padding; -// FlexLayoutAlgorithm algorithm(Style(), MainAxisLength(), flex_items); // while ((FlexLine* line = algorithm.ComputenextLine(LogicalWidth()))) { // // Compute main axis size, using sum_hypothetical_main_size if // // indefinite @@ -264,9 +263,14 @@ // // The final position of each flex item is in item.desired_location class FlexLayoutAlgorithm { public: - FlexLayoutAlgorithm(const ComputedStyle*, - LayoutUnit line_break_length, - FlexItemVector& all_items); + FlexLayoutAlgorithm(const ComputedStyle*, LayoutUnit line_break_length); + + template <typename... Args> + FlexItem& emplace_back(Args&&... args) { + FlexItem& item = all_items_.emplace_back(std::forward<Args>(args)...); + item.algorithm = this; + return item; + } const ComputedStyle* Style() const { return style_; } const ComputedStyle& StyleRef() const { return *style_; } @@ -305,7 +309,7 @@ const ComputedStyle* style_; const LayoutUnit line_break_length_; - FlexItemVector& all_items_; + FlexItemVector all_items_; Vector<FlexLine> flex_lines_; size_t next_item_index_; DISALLOW_COPY_AND_ASSIGN(FlexLayoutAlgorithm);
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index b37b3b1..8625714 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -486,20 +486,48 @@ ClearNeedsLayout(); } -void LayoutBlock::AddOverflowFromChildren() { +void LayoutBlock::AddVisualOverflowFromChildren() { if (ChildrenInline()) - ToLayoutBlockFlow(this)->AddOverflowFromInlineChildren(); + ToLayoutBlockFlow(this)->AddVisualOverflowFromInlineChildren(); else - AddOverflowFromBlockChildren(); + AddVisualOverflowFromBlockChildren(); +} + +void LayoutBlock::AddLayoutOverflowFromChildren() { + if (ChildrenInline()) + ToLayoutBlockFlow(this)->AddLayoutOverflowFromInlineChildren(); + else + AddLayoutOverflowFromBlockChildren(); +} + +void LayoutBlock::ComputeOverflow(LayoutUnit old_client_after_edge, + bool recompute_floats) { + LayoutRect previous_visual_overflow_rect = VisualOverflowRect(); + overflow_.reset(); + ComputeLayoutOverflow(old_client_after_edge, recompute_floats); + ComputeVisualOverflow(previous_visual_overflow_rect, recompute_floats); +} + +void LayoutBlock::ComputeVisualOverflow( + const LayoutRect& previous_visual_overflow_rect, + bool) { + AddVisualOverflowFromChildren(); + + AddVisualEffectOverflow(); + AddVisualOverflowFromTheme(); + + if (VisualOverflowRect() != previous_visual_overflow_rect) { + if (Layer()) + Layer()->SetNeedsCompositingInputsUpdate(); + GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired); + } } DISABLE_CFI_PERF -void LayoutBlock::ComputeOverflow(LayoutUnit old_client_after_edge, bool) { - LayoutRect previous_visual_overflow_rect = VisualOverflowRect(); - overflow_.reset(); - - AddOverflowFromChildren(); - AddOverflowFromPositionedObjects(); +void LayoutBlock::ComputeLayoutOverflow(LayoutUnit old_client_after_edge, + bool) { + AddLayoutOverflowFromChildren(); + AddLayoutOverflowFromPositionedObjects(); if (HasOverflowClip()) { // When we have overflow clip, propagate the original spillout since it will @@ -521,18 +549,9 @@ if (HasOverflowModel()) overflow_->SetLayoutClientAfterEdge(old_client_after_edge); } - - AddVisualEffectOverflow(); - AddVisualOverflowFromTheme(); - - if (VisualOverflowRect() != previous_visual_overflow_rect) { - if (Layer()) - Layer()->SetNeedsCompositingInputsUpdate(); - GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired); - } } -void LayoutBlock::AddOverflowFromBlockChildren() { +void LayoutBlock::AddVisualOverflowFromBlockChildren() { for (LayoutBox* child = FirstChildBox(); child; child = child->NextSiblingBox()) { if (child->IsFloatingOrOutOfFlowPositioned() || child->IsColumnSpanAll()) @@ -545,23 +564,45 @@ // the outline which may enclose continuations. if (child->IsLayoutBlockFlow() && ToLayoutBlockFlow(child)->ContainsInlineWithOutlineAndContinuation()) - ToLayoutBlockFlow(child)->AddOverflowFromInlineChildren(); + ToLayoutBlockFlow(child)->AddVisualOverflowFromInlineChildren(); - AddOverflowFromChild(*child); + AddVisualOverflowFromChild(*child); } } -void LayoutBlock::AddOverflowFromPositionedObjects() { +void LayoutBlock::AddLayoutOverflowFromBlockChildren() { + for (LayoutBox* child = FirstChildBox(); child; + child = child->NextSiblingBox()) { + if (child->IsFloatingOrOutOfFlowPositioned() || child->IsColumnSpanAll()) + continue; + + // If the child contains inline with outline and continuation, its + // visual overflow computed during its layout might be inaccurate because + // the layout of continuations might not be up-to-date at that time. + // Re-add overflow from inline children to ensure its overflow covers + // the outline which may enclose continuations. + if (child->IsLayoutBlockFlow() && + ToLayoutBlockFlow(child)->ContainsInlineWithOutlineAndContinuation()) + ToLayoutBlockFlow(child)->AddLayoutOverflowFromInlineChildren(); + + AddLayoutOverflowFromChild(*child); + } +} + +void LayoutBlock::AddLayoutOverflowFromPositionedObjects() { TrackedLayoutBoxListHashSet* positioned_descendants = PositionedObjects(); if (!positioned_descendants) return; for (auto* positioned_object : *positioned_descendants) { - // Fixed positioned elements don't contribute to layout overflow, since they - // don't scroll with the content. - if (positioned_object->StyleRef().GetPosition() != EPosition::kFixed) - AddOverflowFromChild(*positioned_object, - ToLayoutSize(positioned_object->Location())); + // Fixed positioned elements whose containing block is the LayoutView + // don't contribute to layout overflow, since they don't scroll with the + // content. + if (!IsLayoutView() || + positioned_object->StyleRef().GetPosition() != EPosition::kFixed) { + AddLayoutOverflowFromChild(*positioned_object, + ToLayoutSize(positioned_object->Location())); + } } }
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h index 847919f..fb9ba1b 100644 --- a/third_party/blink/renderer/core/layout/layout_block.h +++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -395,6 +395,9 @@ const LayoutPoint& paint_offset) const; void UpdateAfterLayout() override; + void ComputeOverflow(LayoutUnit old_client_after_edge, + bool recompute_floats = false); + protected: virtual void AdjustInlineDirectionLineBounds( unsigned /* expansionOpportunityCount */, @@ -444,15 +447,21 @@ bool SimplifiedLayout(); virtual void SimplifiedNormalFlowLayout(); - public: - virtual void ComputeOverflow(LayoutUnit old_client_after_edge, - bool recompute_floats = false); + private: + void AddVisualOverflowFromBlockChildren(); + void AddVisualOverflowFromTheme(); + void AddLayoutOverflowFromPositionedObjects(); + void AddLayoutOverflowFromBlockChildren(); protected: - virtual void AddOverflowFromChildren(); - void AddOverflowFromPositionedObjects(); - void AddOverflowFromBlockChildren(); - void AddVisualOverflowFromTheme(); + virtual void ComputeVisualOverflow( + const LayoutRect& previous_visual_overflow_rect, + bool recompute_floats); + virtual void ComputeLayoutOverflow(LayoutUnit old_client_after_edge, + bool recompute_floats); + + virtual void AddLayoutOverflowFromChildren(); + virtual void AddVisualOverflowFromChildren(); void AddOutlineRects(Vector<LayoutRect>&, const LayoutPoint& additional_offset,
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc index 3eada8a..8759488 100644 --- a/third_party/blink/renderer/core/layout/layout_block_flow.cc +++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -2509,20 +2509,31 @@ : EBreakBetween::kAuto; } -void LayoutBlockFlow::AddOverflowFromFloats() { +void LayoutBlockFlow::AddVisualOverflowFromFloats() { if (!floating_objects_) return; - const FloatingObjectSet& floating_object_set = floating_objects_->Set(); - FloatingObjectSetIterator end = floating_object_set.end(); - for (FloatingObjectSetIterator it = floating_object_set.begin(); it != end; - ++it) { - const FloatingObject& floating_object = *it->get(); - if (floating_object.IsDescendant()) - AddOverflowFromChild( - *floating_object.GetLayoutObject(), - LayoutSize(XPositionForFloatIncludingMargin(floating_object), - YPositionForFloatIncludingMargin(floating_object))); + for (auto& floating_object : floating_objects_->Set()) { + if (floating_object->IsDescendant()) { + AddVisualOverflowFromChild( + *floating_object->GetLayoutObject(), + LayoutSize(XPositionForFloatIncludingMargin(*floating_object), + YPositionForFloatIncludingMargin(*floating_object))); + } + } +} + +void LayoutBlockFlow::AddLayoutOverflowFromFloats() { + if (!floating_objects_) + return; + + for (auto& floating_object : floating_objects_->Set()) { + if (floating_object->IsDescendant()) { + AddLayoutOverflowFromChild( + *floating_object->GetLayoutObject(), + LayoutSize(XPositionForFloatIncludingMargin(*floating_object), + YPositionForFloatIncludingMargin(*floating_object))); + } } } @@ -2552,12 +2563,24 @@ scoped_refptr<const NGPhysicalFragment>, NGPhysicalOffset) {} -void LayoutBlockFlow::ComputeOverflow(LayoutUnit old_client_after_edge, - bool recompute_floats) { - LayoutBlock::ComputeOverflow(old_client_after_edge, recompute_floats); +void LayoutBlockFlow::ComputeVisualOverflow( + const LayoutRect& previous_visual_overflow_rect, + bool recompute_floats) { + LayoutBlock::ComputeVisualOverflow(previous_visual_overflow_rect, + recompute_floats); if (recompute_floats || CreatesNewFormattingContext() || HasSelfPaintingLayer()) - AddOverflowFromFloats(); + AddVisualOverflowFromFloats(); +} + +void LayoutBlockFlow::ComputeLayoutOverflow(LayoutUnit old_client_after_edge, + bool recompute_floats) { + LayoutBlock::ComputeLayoutOverflow(old_client_after_edge, recompute_floats); + // TODO(chrishtr): why does it check for a self-painting layer? That should + // only apply to visual overflow. + if (recompute_floats || CreatesNewFormattingContext() || + HasSelfPaintingLayer()) + AddLayoutOverflowFromFloats(); } void LayoutBlockFlow::ComputeSelfHitTestRects( @@ -4134,11 +4157,18 @@ // Since the float doesn't overhang, it didn't get put into our list. We // need to go ahead and add its overflow in to the child now. - if (floating_object.IsDescendant()) - child->AddOverflowFromChild( + if (floating_object.IsDescendant()) { + // TODO(chrishtr): this looks weird, is it correct? Also, do we need + // both types of overflow? + child->AddVisualOverflowFromChild( *floating_object.GetLayoutObject(), LayoutSize(XPositionForFloatIncludingMargin(floating_object), YPositionForFloatIncludingMargin(floating_object))); + child->AddLayoutOverflowFromChild( + *floating_object.GetLayoutObject(), + LayoutSize(XPositionForFloatIncludingMargin(floating_object), + YPositionForFloatIncludingMargin(floating_object))); + } } } }
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h index 032f6c31..833be2902 100644 --- a/third_party/blink/renderer/core/layout/layout_block_flow.h +++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -111,8 +111,9 @@ void UpdateBlockLayout(bool relayout_children) override; - void ComputeOverflow(LayoutUnit old_client_after_edge, - bool recompute_floats = false) override; + void ComputeVisualOverflow(const LayoutRect&, bool recompute_floats) override; + void ComputeLayoutOverflow(LayoutUnit old_client_after_edge, + bool recompute_floats) override; void DeleteLineBoxTree(); @@ -318,7 +319,9 @@ rare_data_->multi_column_flow_thread_ = nullptr; } - void AddOverflowFromInlineChildren(); + void AddVisualOverflowFromInlineChildren(); + + void AddLayoutOverflowFromInlineChildren(); // FIXME: This should be const to avoid a const_cast, but can modify child // dirty bits and LayoutTextCombine. @@ -443,9 +446,10 @@ is_self_collapsing_ = CheckIfIsSelfCollapsingBlock(); } - // This function is only public so we can call it from NGBlockNode while we're - // still working on LayoutNG. - void AddOverflowFromFloats(); + // These functions are only public so we can call it from NGBlockNode while + // we're still working on LayoutNG. + void AddVisualOverflowFromFloats(); + void AddLayoutOverflowFromFloats(); virtual NGInlineNodeData* TakeNGInlineNodeData() { return nullptr; } virtual NGInlineNodeData* GetNGInlineNodeData() const { return nullptr; }
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow_line.cc b/third_party/blink/renderer/core/layout/layout_block_flow_line.cc index 0ccc2f3..a27e1170 100644 --- a/third_party/blink/renderer/core/layout/layout_block_flow_line.cc +++ b/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
@@ -2312,7 +2312,7 @@ return !it.AtEnd(); } -void LayoutBlockFlow::AddOverflowFromInlineChildren() { +void LayoutBlockFlow::AddVisualOverflowFromInlineChildren() { LayoutUnit end_padding = HasOverflowClip() ? PaddingEnd() : LayoutUnit(); // FIXME: Need to find another way to do this, since scrollbars could show // when we don't want them to. @@ -2320,7 +2320,6 @@ IsRootEditableElement(*GetNode()) && StyleRef().IsLeftToRightDirection()) end_padding = LayoutUnit(1); for (RootInlineBox* curr = FirstRootBox(); curr; curr = curr->NextRootBox()) { - AddLayoutOverflow(curr->PaddedLayoutOverflowRect(end_padding)); LayoutRect visual_overflow = curr->VisualOverflowRect(curr->LineTop(), curr->LineBottom()); AddContentsVisualOverflow(visual_overflow); @@ -2351,6 +2350,17 @@ AddContentsVisualOverflow(outline_bounds_of_all_continuations); } +void LayoutBlockFlow::AddLayoutOverflowFromInlineChildren() { + LayoutUnit end_padding = HasOverflowClip() ? PaddingEnd() : LayoutUnit(); + // FIXME: Need to find another way to do this, since scrollbars could show + // when we don't want them to. + if (HasOverflowClip() && !end_padding && GetNode() && + IsRootEditableElement(*GetNode()) && StyleRef().IsLeftToRightDirection()) + end_padding = LayoutUnit(1); + for (RootInlineBox* curr = FirstRootBox(); curr; curr = curr->NextRootBox()) + AddLayoutOverflow(curr->PaddedLayoutOverflowRect(end_padding)); +} + void LayoutBlockFlow::DeleteEllipsisLineBoxes() { ETextAlign text_align = StyleRef().GetTextAlign(); IndentTextOrNot indent_text = kIndentText;
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index cdcaa07..9e26e570 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -5266,9 +5266,27 @@ return outsets; } +void LayoutBox::AddVisualOverflowFromChild(const LayoutBox& child, + const LayoutSize& delta) { + // Never allow flow threads to propagate overflow up to a parent. + if (child.IsLayoutFlowThread()) + return; + + // Add in visual overflow from the child. Even if the child clips its + // overflow, it may still have visual overflow of its own set from box shadows + // or reflections. It is unnecessary to propagate this overflow if we are + // clipping our own overflow. + if (child.HasSelfPaintingLayer()) + return; + LayoutRect child_visual_overflow_rect = + child.VisualOverflowRectForPropagation(); + child_visual_overflow_rect.Move(delta); + AddContentsVisualOverflow(child_visual_overflow_rect); +} + DISABLE_CFI_PERF -void LayoutBox::AddOverflowFromChild(const LayoutBox& child, - const LayoutSize& delta) { +void LayoutBox::AddLayoutOverflowFromChild(const LayoutBox& child, + const LayoutSize& delta) { // Never allow flow threads to propagate overflow up to a parent. if (child.IsLayoutFlowThread()) return; @@ -5281,17 +5299,6 @@ child.LayoutOverflowRectForPropagation(this); child_layout_overflow_rect.Move(delta); AddLayoutOverflow(child_layout_overflow_rect); - - // Add in visual overflow from the child. Even if the child clips its - // overflow, it may still have visual overflow of its own set from box shadows - // or reflections. It is unnecessary to propagate this overflow if we are - // clipping our own overflow. - if (child.HasSelfPaintingLayer()) - return; - LayoutRect child_visual_overflow_rect = - child.VisualOverflowRectForPropagation(); - child_visual_overflow_rect.Move(delta); - AddContentsVisualOverflow(child_visual_overflow_rect); } bool LayoutBox::HasTopOverflow() const {
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h index 17800725d..ed52e86 100644 --- a/third_party/blink/renderer/core/layout/layout_box.h +++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -537,10 +537,16 @@ void AddVisualEffectOverflow(); LayoutRectOutsets ComputeVisualEffectOverflowOutsets(); - void AddOverflowFromChild(const LayoutBox& child) { - AddOverflowFromChild(child, child.LocationOffset()); + void AddVisualOverflowFromChild(const LayoutBox& child) { + AddVisualOverflowFromChild(child, child.LocationOffset()); } - void AddOverflowFromChild(const LayoutBox& child, const LayoutSize& delta); + void AddLayoutOverflowFromChild(const LayoutBox& child) { + AddLayoutOverflowFromChild(child, child.LocationOffset()); + } + void AddVisualOverflowFromChild(const LayoutBox& child, + const LayoutSize& delta); + void AddLayoutOverflowFromChild(const LayoutBox& child, + const LayoutSize& delta); void ClearLayoutOverflow(); void ClearAllOverflows() { overflow_.reset(); }
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc index 0c7748b..c24084b 100644 --- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc +++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -818,7 +818,8 @@ // TODO(cbiesinger): That second part is not yet true. ChildLayoutType layout_type = relayout_children ? kForceLayout : kLayoutIfNeeded; - FlexItemVector all_items; + const LayoutUnit line_break_length = MainAxisContentExtent(LayoutUnit::Max()); + FlexLayoutAlgorithm flex_algorithm(Style(), line_break_length); order_iterator_.First(); for (LayoutBox* child = order_iterator_.CurrentChild(); child; child = order_iterator_.Next()) { @@ -828,11 +829,9 @@ continue; } - all_items.push_back(ConstructFlexItem(*child, layout_type)); + flex_algorithm.emplace_back(ConstructFlexItem(*child, layout_type)); } - const LayoutUnit line_break_length = MainAxisContentExtent(LayoutUnit::Max()); - FlexLayoutAlgorithm flex_algorithm(Style(), line_break_length, all_items); LayoutUnit cross_axis_offset = FlowAwareContentInsetBefore(); LayoutUnit logical_width = LogicalWidth(); FlexLine* current_line;
diff --git a/third_party/blink/renderer/core/layout/layout_list_item.cc b/third_party/blink/renderer/core/layout/layout_list_item.cc index 1a1b193..f2a7ed1 100644 --- a/third_party/blink/renderer/core/layout/layout_list_item.cc +++ b/third_party/blink/renderer/core/layout/layout_list_item.cc
@@ -289,9 +289,14 @@ return false; } -void LayoutListItem::AddOverflowFromChildren() { - LayoutBlockFlow::AddOverflowFromChildren(); - PositionListMarker(); +void LayoutListItem::AddVisualOverflowFromChildren() { + LayoutBlockFlow::AddVisualOverflowFromChildren(); + UpdateOverflow(Visual); +} + +void LayoutListItem::AddLayoutOverflowFromChildren() { + LayoutBlockFlow::AddLayoutOverflowFromChildren(); + UpdateOverflow(Layout); } // Align marker_inline_box in block direction according to line_box_root's @@ -365,53 +370,54 @@ } } -void LayoutListItem::PositionListMarker() { - if (marker_ && marker_->Parent() && marker_->Parent()->IsBox() && - !marker_->IsInside() && marker_->InlineBoxWrapper()) { - if (need_block_direction_align_) - AlignMarkerInBlockDirection(); +void LayoutListItem::UpdateOverflow(OverflowType overflow_type) { + if (!marker_ || !marker_->Parent() || !marker_->Parent()->IsBox() || + marker_->IsInside() || !marker_->InlineBoxWrapper()) + return; - LayoutUnit marker_old_logical_left = marker_->LogicalLeft(); - LayoutUnit block_offset; - LayoutUnit line_offset; - for (LayoutBox* o = marker_->ParentBox(); o != this; o = o->ParentBox()) { - block_offset += o->LogicalTop(); - line_offset += o->LogicalLeft(); - } + if (need_block_direction_align_) + AlignMarkerInBlockDirection(); - bool adjust_overflow = false; - LayoutUnit marker_logical_left; - InlineBox* marker_inline_box = marker_->InlineBoxWrapper(); - RootInlineBox& root = marker_inline_box->Root(); - bool hit_self_painting_layer = false; + LayoutUnit marker_old_logical_left = marker_->LogicalLeft(); + LayoutUnit block_offset; + LayoutUnit line_offset; + for (LayoutBox* o = marker_->ParentBox(); o != this; o = o->ParentBox()) { + block_offset += o->LogicalTop(); + line_offset += o->LogicalLeft(); + } - LayoutUnit line_top = root.LineTop(); - LayoutUnit line_bottom = root.LineBottom(); + bool adjust_overflow = false; + LayoutUnit marker_logical_left; + InlineBox* marker_inline_box = marker_->InlineBoxWrapper(); + RootInlineBox& root = marker_inline_box->Root(); + bool hit_self_painting_layer = false; - // We figured out the inline position of the marker before laying out the - // line so that floats later in the line don't interfere with it. However - // if the line has shifted down then that position will be too far out. - // So we always take the lowest value of (1) the position of the marker - // if we calculate it now and (2) the inline position we calculated before - // laying out the line. - // TODO(jchaffraix): Propagating the overflow to the line boxes seems - // pretty wrong (https://crbug.com/554160). - // FIXME: Need to account for relative positioning in the layout overflow. - if (StyleRef().IsLeftToRightDirection()) { - LayoutUnit marker_line_offset = - std::min(marker_->LineOffset(), - LogicalLeftOffsetForLine(marker_->LogicalTop(), - kDoNotIndentText, LayoutUnit())); - marker_logical_left = marker_line_offset - line_offset - PaddingStart() - - BorderStart() + marker_->MarginStart(); - marker_inline_box->MoveInInlineDirection(marker_logical_left - - marker_old_logical_left); - for (InlineFlowBox* box = marker_inline_box->Parent(); box; - box = box->Parent()) { + LayoutUnit line_top = root.LineTop(); + LayoutUnit line_bottom = root.LineBottom(); + + // We figured out the inline position of the marker before laying out the + // line so that floats later in the line don't interfere with it. However + // if the line has shifted down then that position will be too far out. + // So we always take the lowest value of (1) the position of the marker + // if we calculate it now and (2) the inline position we calculated before + // laying out the line. + // TODO(jchaffraix): Propagating the overflow to the line boxes seems + // pretty wrong (https://crbug.com/554160). + // FIXME: Need to account for relative positioning in the layout overflow. + if (StyleRef().IsLeftToRightDirection()) { + LayoutUnit marker_line_offset = + std::min(marker_->LineOffset(), + LogicalLeftOffsetForLine(marker_->LogicalTop(), + kDoNotIndentText, LayoutUnit())); + marker_logical_left = marker_line_offset - line_offset - PaddingStart() - + BorderStart() + marker_->MarginStart(); + marker_inline_box->MoveInInlineDirection(marker_logical_left - + marker_old_logical_left); + for (InlineFlowBox* box = marker_inline_box->Parent(); box; + box = box->Parent()) { + if (overflow_type == Visual) { LayoutRect new_logical_visual_overflow_rect = box->LogicalVisualOverflowRect(line_top, line_bottom); - LayoutRect new_logical_layout_overflow_rect = - box->LogicalLayoutOverflowRect(line_top, line_bottom); if (marker_logical_left < new_logical_visual_overflow_rect.X() && !hit_self_painting_layer) { new_logical_visual_overflow_rect.SetWidth( @@ -420,6 +426,14 @@ if (box == root) adjust_overflow = true; } + box->OverrideVisualOverflowFromLogicalRect( + new_logical_visual_overflow_rect, line_top, line_bottom); + + if (box->BoxModelObject().HasSelfPaintingLayer()) + hit_self_painting_layer = true; + } else { + LayoutRect new_logical_layout_overflow_rect = + box->LogicalLayoutOverflowRect(line_top, line_bottom); if (marker_logical_left < new_logical_layout_overflow_rect.X()) { new_logical_layout_overflow_rect.SetWidth( new_logical_layout_overflow_rect.MaxX() - marker_logical_left); @@ -427,27 +441,24 @@ if (box == root) adjust_overflow = true; } - box->OverrideOverflowFromLogicalRects(new_logical_layout_overflow_rect, - new_logical_visual_overflow_rect, - line_top, line_bottom); - if (box->BoxModelObject().HasSelfPaintingLayer()) - hit_self_painting_layer = true; + box->OverrideLayoutOverflowFromLogicalRect( + new_logical_layout_overflow_rect, line_top, line_bottom); } - } else { - LayoutUnit marker_line_offset = - std::max(marker_->LineOffset(), - LogicalRightOffsetForLine(marker_->LogicalTop(), - kDoNotIndentText, LayoutUnit())); - marker_logical_left = marker_line_offset - line_offset + PaddingStart() + - BorderStart() + marker_->MarginEnd(); - marker_inline_box->MoveInInlineDirection(marker_logical_left - - marker_old_logical_left); - for (InlineFlowBox* box = marker_inline_box->Parent(); box; - box = box->Parent()) { + } + } else { + LayoutUnit marker_line_offset = + std::max(marker_->LineOffset(), + LogicalRightOffsetForLine(marker_->LogicalTop(), + kDoNotIndentText, LayoutUnit())); + marker_logical_left = marker_line_offset - line_offset + PaddingStart() + + BorderStart() + marker_->MarginEnd(); + marker_inline_box->MoveInInlineDirection(marker_logical_left - + marker_old_logical_left); + for (InlineFlowBox* box = marker_inline_box->Parent(); box; + box = box->Parent()) { + if (overflow_type == Visual) { LayoutRect new_logical_visual_overflow_rect = box->LogicalVisualOverflowRect(line_top, line_bottom); - LayoutRect new_logical_layout_overflow_rect = - box->LogicalLayoutOverflowRect(line_top, line_bottom); if (marker_logical_left + marker_->LogicalWidth() > new_logical_visual_overflow_rect.MaxX() && !hit_self_painting_layer) { @@ -457,6 +468,14 @@ if (box == root) adjust_overflow = true; } + box->OverrideVisualOverflowFromLogicalRect( + new_logical_visual_overflow_rect, line_top, line_bottom); + + if (box->BoxModelObject().HasSelfPaintingLayer()) + hit_self_painting_layer = true; + } else { + LayoutRect new_logical_layout_overflow_rect = + box->LogicalLayoutOverflowRect(line_top, line_bottom); if (marker_logical_left + marker_->LogicalWidth() > new_logical_layout_overflow_rect.MaxX()) { new_logical_layout_overflow_rect.SetWidth( @@ -465,45 +484,43 @@ if (box == root) adjust_overflow = true; } - box->OverrideOverflowFromLogicalRects(new_logical_layout_overflow_rect, - new_logical_visual_overflow_rect, - line_top, line_bottom); - - if (box->BoxModelObject().HasSelfPaintingLayer()) - hit_self_painting_layer = true; + box->OverrideLayoutOverflowFromLogicalRect( + new_logical_layout_overflow_rect, line_top, line_bottom); } } + } - if (adjust_overflow) { - // AlignMarkerInBlockDirection and pagination_strut might move root or - // marker_inline_box in block direction. We should add marker_inline_box - // top when propagate overflow. - LayoutRect marker_rect( - LayoutPoint(marker_logical_left + line_offset, - block_offset + marker_inline_box->LogicalTop()), - marker_->Size()); - if (!StyleRef().IsHorizontalWritingMode()) - marker_rect = marker_rect.TransposedRect(); - LayoutBox* o = marker_; - bool propagate_visual_overflow = true; - bool propagate_layout_overflow = true; + if (adjust_overflow) { + // AlignMarkerInBlockDirection and pagination_strut might move root or + // marker_inline_box in block direction. We should add marker_inline_box + // top when propagate overflow. + LayoutRect marker_rect( + LayoutPoint(marker_logical_left + line_offset, + block_offset + marker_inline_box->LogicalTop()), + marker_->Size()); + if (!StyleRef().IsHorizontalWritingMode()) + marker_rect = marker_rect.TransposedRect(); + LayoutBox* o = marker_; + + if (overflow_type == Visual) { + do { + o = o->ParentBox(); + if (o->IsLayoutBlock()) + ToLayoutBlock(o)->AddContentsVisualOverflow(marker_rect); + if (o->HasOverflowClip() || o->HasSelfPaintingLayer()) + break; + marker_rect.MoveBy(-o->Location()); + } while (o != this); + } else { do { o = o->ParentBox(); if (o->IsLayoutBlock()) { - if (propagate_visual_overflow) - ToLayoutBlock(o)->AddContentsVisualOverflow(marker_rect); - if (propagate_layout_overflow) - ToLayoutBlock(o)->AddLayoutOverflow(marker_rect); + ToLayoutBlock(o)->AddLayoutOverflow(marker_rect); } - if (o->HasOverflowClip()) { - propagate_layout_overflow = false; - propagate_visual_overflow = false; - } - if (o->HasSelfPaintingLayer()) - propagate_visual_overflow = false; + if (o->HasOverflowClip()) + break; marker_rect.MoveBy(-o->Location()); - } while (o != this && propagate_visual_overflow && - propagate_layout_overflow); + } while (o != this); } } }
diff --git a/third_party/blink/renderer/core/layout/layout_list_item.h b/third_party/blink/renderer/core/layout/layout_list_item.h index a1bd9f9..e180df75 100644 --- a/third_party/blink/renderer/core/layout/layout_list_item.h +++ b/third_party/blink/renderer/core/layout/layout_list_item.h
@@ -65,11 +65,13 @@ // Returns true if we re-attached and updated the location of the marker. bool UpdateMarkerLocation(); - void PositionListMarker(); + enum OverflowType { Layout, Visual }; + void UpdateOverflow(OverflowType); void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override; - void AddOverflowFromChildren() override; + void AddVisualOverflowFromChildren() override; + void AddLayoutOverflowFromChildren() override; void AlignMarkerInBlockDirection();
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc index 5d3fcefb..a7ae137 100644 --- a/third_party/blink/renderer/core/layout/layout_multi_column_set.cc +++ b/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
@@ -520,7 +520,21 @@ return result; } -void LayoutMultiColumnSet::AddOverflowFromChildren() { +void LayoutMultiColumnSet::AddVisualOverflowFromChildren() { + // It's useless to calculate overflow if we haven't determined the page + // logical height yet. + if (!IsPageLogicalHeightKnown()) + return; + LayoutRect overflow_rect; + for (const auto& group : fragmentainer_groups_) { + LayoutRect rect = group.CalculateOverflow(); + rect.Move(group.OffsetFromColumnSet()); + overflow_rect.Unite(rect); + } + AddContentsVisualOverflow(overflow_rect); +} + +void LayoutMultiColumnSet::AddLayoutOverflowFromChildren() { // It's useless to calculate overflow if we haven't determined the page // logical height yet. if (!IsPageLogicalHeightKnown()) @@ -532,7 +546,6 @@ overflow_rect.Unite(rect); } AddLayoutOverflow(overflow_rect); - AddContentsVisualOverflow(overflow_rect); } void LayoutMultiColumnSet::InsertedIntoTree() {
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_set.h b/third_party/blink/renderer/core/layout/layout_multi_column_set.h index 91612c05..8dbe3d27 100644 --- a/third_party/blink/renderer/core/layout/layout_multi_column_set.h +++ b/third_party/blink/renderer/core/layout/layout_multi_column_set.h
@@ -255,7 +255,8 @@ void PaintObject(const PaintInfo&, const LayoutPoint& paint_offset) const override; - void AddOverflowFromChildren() override; + void AddVisualOverflowFromChildren() override; + void AddLayoutOverflowFromChildren() override; MultiColumnFragmentainerGroupList fragmentainer_groups_; LayoutFlowThread* flow_thread_;
diff --git a/third_party/blink/renderer/core/layout/layout_table.cc b/third_party/blink/renderer/core/layout/layout_table.cc index 1625cca8..c28b0e7 100644 --- a/third_party/blink/renderer/core/layout/layout_table.cc +++ b/third_party/blink/renderer/core/layout/layout_table.cc
@@ -910,7 +910,38 @@ } } -void LayoutTable::AddOverflowFromChildren() { +void LayoutTable::AddVisualOverflowFromChildren() { + // Add overflow from borders. + // Technically it's odd that we are incorporating the borders into layout + // overflow, which is only supposed to be about overflow from our + // descendant objects, but since tables don't support overflow:auto, this + // works out fine. + UpdateCollapsedOuterBorders(); + if (ShouldCollapseBorders() && (collapsed_outer_border_start_overflow_ || + collapsed_outer_border_end_overflow_)) { + LogicalToPhysical<LayoutUnit> physical_border_overflow( + StyleRef().GetWritingMode(), StyleRef().Direction(), + LayoutUnit(collapsed_outer_border_start_overflow_), + LayoutUnit(collapsed_outer_border_end_overflow_), LayoutUnit(), + LayoutUnit()); + LayoutRect border_overflow(PixelSnappedBorderBoxRect()); + border_overflow.Expand(LayoutRectOutsets( + physical_border_overflow.Top(), physical_border_overflow.Right(), + physical_border_overflow.Bottom(), physical_border_overflow.Left())); + AddSelfVisualOverflow(border_overflow); + } + + // Add overflow from our caption. + for (auto* caption : captions_) + AddVisualOverflowFromChild(*caption); + + // Add overflow from our sections. + for (LayoutTableSection* section = TopSection(); section; + section = SectionBelow(section)) + AddVisualOverflowFromChild(*section); +} + +void LayoutTable::AddLayoutOverflowFromChildren() { // Add overflow from borders. // Technically it's odd that we are incorporating the borders into layout // overflow, which is only supposed to be about overflow from our @@ -929,17 +960,16 @@ physical_border_overflow.Top(), physical_border_overflow.Right(), physical_border_overflow.Bottom(), physical_border_overflow.Left())); AddLayoutOverflow(border_overflow); - AddSelfVisualOverflow(border_overflow); } // Add overflow from our caption. for (unsigned i = 0; i < captions_.size(); i++) - AddOverflowFromChild(*captions_[i]); + AddLayoutOverflowFromChild(*captions_[i]); // Add overflow from our sections. for (LayoutTableSection* section = TopSection(); section; section = SectionBelow(section)) - AddOverflowFromChild(*section); + AddLayoutOverflowFromChild(*section); } void LayoutTable::PaintObject(const PaintInfo& paint_info,
diff --git a/third_party/blink/renderer/core/layout/layout_table.h b/third_party/blink/renderer/core/layout/layout_table.h index 87340b08..48af1bc 100644 --- a/third_party/blink/renderer/core/layout/layout_table.h +++ b/third_party/blink/renderer/core/layout/layout_table.h
@@ -474,7 +474,8 @@ OverlayScrollbarClipBehavior = kIgnorePlatformOverlayScrollbarSize) const override; - void AddOverflowFromChildren() override; + void AddVisualOverflowFromChildren() override; + void AddLayoutOverflowFromChildren() override; void RecalcSections() const;
diff --git a/third_party/blink/renderer/core/layout/layout_table_cell.cc b/third_party/blink/renderer/core/layout/layout_table_cell.cc index 9c7f0761f..9c85ac7 100644 --- a/third_party/blink/renderer/core/layout/layout_table_cell.cc +++ b/third_party/blink/renderer/core/layout/layout_table_cell.cc
@@ -381,9 +381,11 @@ } } -void LayoutTableCell::ComputeOverflow(LayoutUnit old_client_after_edge, - bool recompute_floats) { - LayoutBlockFlow::ComputeOverflow(old_client_after_edge, recompute_floats); +void LayoutTableCell::ComputeVisualOverflow( + const LayoutRect& previous_visual_overflow_rect, + bool recompute_floats) { + LayoutBlockFlow::ComputeVisualOverflow(previous_visual_overflow_rect, + recompute_floats); UpdateCollapsedBorderValues(); if (!collapsed_border_values_)
diff --git a/third_party/blink/renderer/core/layout/layout_table_cell.h b/third_party/blink/renderer/core/layout/layout_table_cell.h index 44dedd1..e369526c 100644 --- a/third_party/blink/renderer/core/layout/layout_table_cell.h +++ b/third_party/blink/renderer/core/layout/layout_table_cell.h
@@ -341,8 +341,7 @@ return is_spanning_collapsed_column_; } - void ComputeOverflow(LayoutUnit old_client_after_edge, - bool recompute_floats = false) override; + void ComputeVisualOverflow(const LayoutRect&, bool recompute_floats) override; protected: void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
diff --git a/third_party/blink/renderer/core/layout/layout_table_section.cc b/third_party/blink/renderer/core/layout/layout_table_section.cc index bb44faf4..fe70f5d 100644 --- a/third_party/blink/renderer/core/layout/layout_table_section.cc +++ b/third_party/blink/renderer/core/layout/layout_table_section.cc
@@ -1361,6 +1361,22 @@ } void LayoutTableSection::ComputeOverflowFromDescendants() { + auto old_self_visual_overflow_rect = SelfVisualOverflowRect(); + overflow_.reset(); + overflowing_cells_.clear(); + force_full_paint_ = false; + + ComputeVisualOverflowFromDescendants(); + + // Overflow rect contributes to the visual rect, so if it has changed then we + // need to signal a possible paint invalidation. + if (old_self_visual_overflow_rect != SelfVisualOverflowRect()) + SetShouldCheckForPaintInvalidation(); + + ComputeLayoutOverflowFromDescendants(); +} + +void LayoutTableSection::ComputeVisualOverflowFromDescendants() { // These 2 variables are used to balance the memory consumption vs the paint // time on big sections with overflowing cells: // 1. For small sections, don't track overflowing cells because for them the @@ -1379,17 +1395,13 @@ total_cell_count < kMinCellCountToUsePartialPaint ? 0 : kMaxOverflowingCellRatioForPartialPaint * total_cell_count; - auto old_overflow_rect = SelfVisualOverflowRect(); - overflow_.reset(); - overflowing_cells_.clear(); - force_full_paint_ = false; #if DCHECK_IS_ON() bool has_overflowing_cell = false; #endif for (auto* row = FirstRow(); row; row = row->NextRow()) { - AddOverflowFromChild(*row); + AddVisualOverflowFromChild(*row); for (auto* cell = row->FirstCell(); cell; cell = cell->NextCell()) { // Let the section's self visual overflow cover the cell's whole collapsed @@ -1422,16 +1434,17 @@ overflowing_cells_.insert(cell); } } - // Overflow rect contributes to the visual rect, so if it has changed then we - // need to signal a possible paint invalidation. - if (old_overflow_rect != SelfVisualOverflowRect()) - SetShouldCheckForPaintInvalidation(); #if DCHECK_IS_ON() DCHECK_EQ(has_overflowing_cell, HasOverflowingCell()); #endif } +void LayoutTableSection::ComputeLayoutOverflowFromDescendants() { + for (auto* row = FirstRow(); row; row = row->NextRow()) + AddLayoutOverflowFromChild(*row); +} + bool LayoutTableSection::RecalcOverflow() { if (!ChildNeedsOverflowRecalc()) return false;
diff --git a/third_party/blink/renderer/core/layout/layout_table_section.h b/third_party/blink/renderer/core/layout/layout_table_section.h index 438a0dd..364313c 100644 --- a/third_party/blink/renderer/core/layout/layout_table_section.h +++ b/third_party/blink/renderer/core/layout/layout_table_section.h
@@ -299,6 +299,9 @@ HitTestAction) override; private: + void ComputeVisualOverflowFromDescendants(); + void ComputeLayoutOverflowFromDescendants(); + bool IsOfType(LayoutObjectType type) const override { return type == kLayoutObjectTableSection || LayoutBox::IsOfType(type); }
diff --git a/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc b/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc index 4774cfd..79a43d1 100644 --- a/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc +++ b/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
@@ -313,12 +313,6 @@ InnerEditorElement()->setScrollTop(new_top); } -void LayoutTextControlSingleLine::AddOverflowFromChildren() { - // If the INPUT content height is smaller than the font height, the - // inner-editor element overflows the INPUT box intentionally, however it - // shouldn't affect outside of the INPUT box. So we ignore child overflow. -} - HTMLInputElement* LayoutTextControlSingleLine::InputElement() const { return ToHTMLInputElement(GetNode()); }
diff --git a/third_party/blink/renderer/core/layout/layout_text_control_single_line.h b/third_party/blink/renderer/core/layout/layout_text_control_single_line.h index 02347ad0..9132a9e 100644 --- a/third_party/blink/renderer/core/layout/layout_text_control_single_line.h +++ b/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
@@ -77,7 +77,12 @@ LayoutUnit ComputeControlLogicalHeight( LayoutUnit line_height, LayoutUnit non_content_height) const override; - void AddOverflowFromChildren() final; + + // If the INPUT content height is smaller than the font height, the + // inner-editor element overflows the INPUT box intentionally, however it + // shouldn't affect outside of the INPUT box. So we ignore child overflow. + void AddVisualOverflowFromChildren() final {} + void AddLayoutOverflowFromChildren() final {} bool AllowsOverflowClip() const override { return false; }
diff --git a/third_party/blink/renderer/core/layout/line/inline_flow_box.cc b/third_party/blink/renderer/core/layout/line/inline_flow_box.cc index b1ac299..46ff879 100644 --- a/third_party/blink/renderer/core/layout/line/inline_flow_box.cc +++ b/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
@@ -918,6 +918,28 @@ } } +void InlineFlowBox::OverrideVisualOverflowFromLogicalRect( + const LayoutRect& logical_visual_overflow, + LayoutUnit line_top, + LayoutUnit line_bottom) { + // If we are setting an overflow, then we can't pretend not to have an + // overflow. + ClearKnownToHaveNoOverflow(); + SetVisualOverflowFromLogicalRect(logical_visual_overflow, line_top, + line_bottom); +} + +void InlineFlowBox::OverrideLayoutOverflowFromLogicalRect( + const LayoutRect& logical_layout_overflow, + LayoutUnit line_top, + LayoutUnit line_bottom) { + // If we are setting an overflow, then we can't pretend not to have an + // overflow. + ClearKnownToHaveNoOverflow(); + SetLayoutOverflowFromLogicalRect(logical_layout_overflow, line_top, + line_bottom); +} + LayoutUnit InlineFlowBox::FarthestPositionForUnderline( LineLayoutItem decorating_box, FontVerticalPositionType position_type, @@ -1233,8 +1255,10 @@ } } - SetOverflowFromLogicalRects(logical_layout_overflow, logical_visual_overflow, - line_top, line_bottom); + SetLayoutOverflowFromLogicalRect(logical_layout_overflow, line_top, + line_bottom); + SetVisualOverflowFromLogicalRect(logical_visual_overflow, line_top, + line_bottom); } void InlineFlowBox::SetLayoutOverflow(const LayoutRect& rect, @@ -1261,23 +1285,29 @@ overflow_->SetVisualOverflow(rect); } -void InlineFlowBox::SetOverflowFromLogicalRects( - const LayoutRect& logical_layout_overflow, +void InlineFlowBox::SetVisualOverflowFromLogicalRect( const LayoutRect& logical_visual_overflow, LayoutUnit line_top, LayoutUnit line_bottom) { DCHECK(!KnownToHaveNoOverflow()); LayoutRect frame_box = FrameRectIncludingLineHeight(line_top, line_bottom); + LayoutRect visual_overflow(IsHorizontal() + ? logical_visual_overflow + : logical_visual_overflow.TransposedRect()); + SetVisualOverflow(visual_overflow, frame_box); +} + +void InlineFlowBox::SetLayoutOverflowFromLogicalRect( + const LayoutRect& logical_layout_overflow, + LayoutUnit line_top, + LayoutUnit line_bottom) { + DCHECK(!KnownToHaveNoOverflow()); + LayoutRect frame_box = FrameRectIncludingLineHeight(line_top, line_bottom); LayoutRect layout_overflow(IsHorizontal() ? logical_layout_overflow : logical_layout_overflow.TransposedRect()); SetLayoutOverflow(layout_overflow, frame_box); - - LayoutRect visual_overflow(IsHorizontal() - ? logical_visual_overflow - : logical_visual_overflow.TransposedRect()); - SetVisualOverflow(visual_overflow, frame_box); } bool InlineFlowBox::NodeAtPoint(HitTestResult& result,
diff --git a/third_party/blink/renderer/core/layout/line/inline_flow_box.h b/third_party/blink/renderer/core/layout/line/inline_flow_box.h index 0aa0f64..7891306c 100644 --- a/third_party/blink/renderer/core/layout/line/inline_flow_box.h +++ b/third_party/blink/renderer/core/layout/line/inline_flow_box.h
@@ -378,19 +378,15 @@ is_first_after_page_break_ = is_first_after_page_break; } - // Some callers (LayoutListItem) needs to set extra overflow on their line - // box. - void OverrideOverflowFromLogicalRects( - const LayoutRect& logical_layout_overflow, + void OverrideVisualOverflowFromLogicalRect( const LayoutRect& logical_visual_overflow, LayoutUnit line_top, - LayoutUnit line_bottom) { - // If we are setting an overflow, then we can't pretend not to have an - // overflow. - ClearKnownToHaveNoOverflow(); - SetOverflowFromLogicalRects(logical_layout_overflow, - logical_visual_overflow, line_top, line_bottom); - } + LayoutUnit line_bottom); + + void OverrideLayoutOverflowFromLogicalRect( + const LayoutRect& logical_layout_overflow, + LayoutUnit line_top, + LayoutUnit line_bottom); LayoutUnit FarthestPositionForUnderline(LineLayoutItem decorating_box, FontVerticalPositionType, @@ -433,10 +429,14 @@ void SetLayoutOverflow(const LayoutRect&, const LayoutRect&); void SetVisualOverflow(const LayoutRect&, const LayoutRect&); - void SetOverflowFromLogicalRects(const LayoutRect& logical_layout_overflow, - const LayoutRect& logical_visual_overflow, - LayoutUnit line_top, - LayoutUnit line_bottom); + void SetLayoutOverflowFromLogicalRect( + const LayoutRect& logical_layout_overflow, + LayoutUnit line_top, + LayoutUnit line_bottom); + void SetVisualOverflowFromLogicalRect( + const LayoutRect& logical_visual_overflow, + LayoutUnit line_top, + LayoutUnit line_bottom); protected: std::unique_ptr<SimpleOverflowModel> overflow_;
diff --git a/third_party/blink/renderer/core/layout/min_max_size.cc b/third_party/blink/renderer/core/layout/min_max_size.cc index c501516..e6980104 100644 --- a/third_party/blink/renderer/core/layout/min_max_size.cc +++ b/third_party/blink/renderer/core/layout/min_max_size.cc
@@ -8,42 +8,6 @@ namespace blink { -void MinMaxSize::Encompass(const MinMaxSize& other) { - min_size = std::max(min_size, other.min_size); - max_size = std::max(max_size, other.max_size); -} - -void MinMaxSize::Encompass(LayoutUnit value) { - min_size = std::max(min_size, value); - max_size = std::max(max_size, value); -} - -void MinMaxSize::Constrain(LayoutUnit value) { - min_size = std::min(min_size, value); - max_size = std::min(max_size, value); -} - -LayoutUnit MinMaxSize::ShrinkToFit(LayoutUnit available_size) const { - DCHECK_GE(max_size, min_size); - return std::min(max_size, std::max(min_size, available_size)); -} - -LayoutUnit MinMaxSize::ClampSizeToMinAndMax(LayoutUnit size) const { - return std::max(min_size, std::min(size, max_size)); -} - -MinMaxSize& MinMaxSize::operator+=(const LayoutUnit length) { - min_size += length; - max_size += length; - return *this; -} - -MinMaxSize& MinMaxSize::operator-=(const LayoutUnit length) { - min_size -= length; - max_size -= length; - return *this; -} - std::ostream& operator<<(std::ostream& stream, const MinMaxSize& value) { return stream << "(" << value.min_size << ", " << value.max_size << ")"; }
diff --git a/third_party/blink/renderer/core/layout/min_max_size.h b/third_party/blink/renderer/core/layout/min_max_size.h index b17ecb6..b8069c11 100644 --- a/third_party/blink/renderer/core/layout/min_max_size.h +++ b/third_party/blink/renderer/core/layout/min_max_size.h
@@ -18,21 +18,35 @@ LayoutUnit max_size; // Make sure that our min/max sizes are at least as large as |other|. - void Encompass(const MinMaxSize& other); + void Encompass(const MinMaxSize& other) { + min_size = std::max(min_size, other.min_size); + max_size = std::max(max_size, other.max_size); + } // Make sure that our min/max sizes are at least as large as |value|. - void Encompass(LayoutUnit value); + void Encompass(LayoutUnit value) { + min_size = std::max(min_size, value); + max_size = std::max(max_size, value); + } // Make sure that our min/max sizes aren't larger than |value|. - void Constrain(LayoutUnit value); + void Constrain(LayoutUnit value) { + min_size = std::min(min_size, value); + max_size = std::min(max_size, value); + } // Interprets the sizes as a min-content/max-content pair and computes the // "shrink-to-fit" size based on them for the given available size. - LayoutUnit ShrinkToFit(LayoutUnit available_size) const; + LayoutUnit ShrinkToFit(LayoutUnit available_size) const { + DCHECK_GE(max_size, min_size); + return std::min(max_size, std::max(min_size, available_size)); + } // Interprets the sizes as a {min-max}-size pair and clamps the given input // size to that. - LayoutUnit ClampSizeToMinAndMax(LayoutUnit) const; + LayoutUnit ClampSizeToMinAndMax(LayoutUnit size) const { + return std::max(min_size, std::min(size, max_size)); + } bool operator==(const MinMaxSize& other) const { return min_size == other.min_size && max_size == other.max_size; @@ -44,8 +58,16 @@ max_size += extra.max_size; return *this; } - MinMaxSize& operator+=(const LayoutUnit); - MinMaxSize& operator-=(const LayoutUnit); + MinMaxSize& operator+=(const LayoutUnit length) { + min_size += length; + max_size += length; + return *this; + } + MinMaxSize& operator-=(const LayoutUnit length) { + min_size -= length; + max_size -= length; + return *this; + } }; CORE_EXPORT std::ostream& operator<<(std::ostream&, const MinMaxSize&);
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc index c3b047c1..78822e0 100644 --- a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc +++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc
@@ -9,20 +9,6 @@ namespace blink { -bool NGBoxStrut::IsEmpty() const { - return *this == NGBoxStrut(); -} - -bool NGBoxStrut::operator==(const NGBoxStrut& other) const { - return std::tie(other.inline_start, other.inline_end, other.block_start, - other.block_end) == - std::tie(inline_start, inline_end, block_start, block_end); -} - -bool NGBoxStrut::operator!=(const NGBoxStrut& other) const { - return !(*this == other); -} - NGPhysicalBoxStrut NGBoxStrut::ConvertToPhysical( WritingMode writing_mode, TextDirection direction) const { @@ -73,17 +59,6 @@ return strut; } -NGLineBoxStrut NGPhysicalBoxStrut::ConvertToLineLogical( - WritingMode writing_mode, - TextDirection direction) const { - return NGLineBoxStrut(ConvertToLogical(writing_mode, direction), - IsFlippedLinesWritingMode(writing_mode)); -} - -LayoutRectOutsets NGPhysicalBoxStrut::ToLayoutRectOutsets() const { - return LayoutRectOutsets(top, right, bottom, left); -} - String NGBoxStrut::ToString() const { return String::Format("Inline: (%d %d) Block: (%d %d)", inline_start.ToInt(), inline_end.ToInt(), block_start.ToInt(), @@ -116,9 +91,8 @@ } } -bool NGLineBoxStrut::operator==(const NGLineBoxStrut& other) const { - return inline_start == other.inline_start && inline_end == other.inline_end && - line_over == other.line_over && line_under == other.line_under; +LayoutRectOutsets NGPhysicalBoxStrut::ToLayoutRectOutsets() const { + return LayoutRectOutsets(top, right, bottom, left); } std::ostream& operator<<(std::ostream& stream, const NGLineBoxStrut& value) { @@ -127,9 +101,4 @@ << ") "; } -NGPixelSnappedPhysicalBoxStrut NGPhysicalBoxStrut::SnapToDevicePixels() const { - return NGPixelSnappedPhysicalBoxStrut(top.Round(), right.Round(), - bottom.Round(), left.Round()); -} - } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h index f4610ed..038ec75 100644 --- a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h +++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
@@ -43,7 +43,7 @@ NGLogicalOffset StartOffset() const { return {inline_start, block_start}; } - bool IsEmpty() const; + bool IsEmpty() const { return *this == NGBoxStrut(); } NGPhysicalBoxStrut ConvertToPhysical(WritingMode, TextDirection) const; @@ -77,8 +77,12 @@ return result; } - bool operator==(const NGBoxStrut& other) const; - bool operator!=(const NGBoxStrut& other) const; + bool operator==(const NGBoxStrut& other) const { + return std::tie(other.inline_start, other.inline_end, other.block_start, + other.block_end) == + std::tie(inline_start, inline_end, block_start, block_end); + } + bool operator!=(const NGBoxStrut& other) const { return !(*this == other); } String ToString() const; @@ -112,7 +116,11 @@ LayoutUnit InlineSum() const { return inline_start + inline_end; } LayoutUnit BlockSum() const { return line_over + line_under; } - bool operator==(const NGLineBoxStrut& other) const; + bool operator==(const NGLineBoxStrut& other) const { + return inline_start == other.inline_start && + inline_end == other.inline_end && line_over == other.line_over && + line_under == other.line_under; + } LayoutUnit inline_start; LayoutUnit inline_end; @@ -122,7 +130,16 @@ CORE_EXPORT std::ostream& operator<<(std::ostream&, const NGLineBoxStrut&); -struct NGPixelSnappedPhysicalBoxStrut; +// Struct to store pixel snapped physical dimensions. +struct CORE_EXPORT NGPixelSnappedPhysicalBoxStrut { + NGPixelSnappedPhysicalBoxStrut() = default; + NGPixelSnappedPhysicalBoxStrut(int top, int right, int bottom, int left) + : top(top), right(right), bottom(bottom), left(left) {} + int top; + int right; + int bottom; + int left; +}; // Struct to store physical dimensions, independent of writing mode and // direction. @@ -141,9 +158,16 @@ // Converts physical dimensions to line-relative logical ones per // https://drafts.csswg.org/css-writing-modes-3/#line-directions - NGLineBoxStrut ConvertToLineLogical(WritingMode, TextDirection) const; + NGLineBoxStrut ConvertToLineLogical(WritingMode writing_mode, + TextDirection direction) const { + return NGLineBoxStrut(ConvertToLogical(writing_mode, direction), + IsFlippedLinesWritingMode(writing_mode)); + } - NGPixelSnappedPhysicalBoxStrut SnapToDevicePixels() const; + NGPixelSnappedPhysicalBoxStrut SnapToDevicePixels() const { + return NGPixelSnappedPhysicalBoxStrut(top.Round(), right.Round(), + bottom.Round(), left.Round()); + } LayoutUnit HorizontalSum() const { return left + right; } LayoutUnit VerticalSum() const { return top + bottom; } @@ -156,17 +180,6 @@ LayoutUnit left; }; -// Struct to store pixel snapped physical dimensions. -struct CORE_EXPORT NGPixelSnappedPhysicalBoxStrut { - NGPixelSnappedPhysicalBoxStrut() = default; - NGPixelSnappedPhysicalBoxStrut(int top, int right, int bottom, int left) - : top(top), right(right), bottom(bottom), left(left) {} - int top; - int right; - int bottom; - int left; -}; - } // namespace blink #endif // NGBoxStrut_h
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.cc index a65589e..50e9985 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.cc
@@ -10,13 +10,9 @@ namespace blink { -bool operator==(const NGBaselineRequest& lhs, const NGBaselineRequest& rhs) { - return lhs.algorithm_type == rhs.algorithm_type && - lhs.baseline_type == rhs.baseline_type; -} - -bool operator!=(const NGBaselineRequest& lhs, const NGBaselineRequest& rhs) { - return !(lhs == rhs); +bool NGBaselineRequest::operator==(const NGBaselineRequest& other) const { + return algorithm_type == other.algorithm_type && + baseline_type == other.baseline_type; } bool NGBaseline::ShouldPropagateBaselines(const NGLayoutInputNode node) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h b/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h index 20a8d99..cfcd9a21 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h
@@ -25,10 +25,12 @@ struct NGBaselineRequest { NGBaselineAlgorithmType algorithm_type; FontBaseline baseline_type; -}; -bool operator==(const NGBaselineRequest&, const NGBaselineRequest&); -bool operator!=(const NGBaselineRequest&, const NGBaselineRequest&); + bool operator==(const NGBaselineRequest& other) const; + bool operator!=(const NGBaselineRequest& other) const { + return !(*this == other); + } +}; // Represents a computed baseline position. struct NGBaseline {
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc index 95a6c324..ce4c4c1 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -66,12 +66,11 @@ } template <typename Base> -void LayoutNGMixin<Base>::AddOverflowFromChildren() { +void LayoutNGMixin<Base>::AddVisualOverflowFromChildren() { // |ComputeOverflow()| calls this, which is called from // |CopyFragmentDataToLayoutBox()| and |RecalcOverflowAfterStyleChange()|. // Add overflow from the last layout cycle. if (const NGPhysicalBoxFragment* physical_fragment = CurrentFragment()) { - AddScrollingOverflowFromChildren(); if (Base::ChildrenInline()) { Base::AddSelfVisualOverflow( physical_fragment->SelfInkOverflow().ToLayoutFlippedRect( @@ -87,7 +86,19 @@ // correctly without RootInlineBox though. } } - Base::AddOverflowFromChildren(); + Base::AddVisualOverflowFromChildren(); +} + +template <typename Base> +void LayoutNGMixin<Base>::AddLayoutOverflowFromChildren() { + // |ComputeOverflow()| calls this, which is called from + // |CopyFragmentDataToLayoutBox()| and |RecalcOverflow()|. + // Add overflow from the last layout cycle. + // TODO(chrishtr): do we need to condition on CurrentFragment()? Why? + if (CurrentFragment()) { + AddScrollingOverflowFromChildren(); + } + Base::AddLayoutOverflowFromChildren(); } template <typename Base>
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h index 3dc73c2..8f1e1e4 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -82,7 +82,8 @@ protected: bool IsOfType(LayoutObject::LayoutObjectType) const override; - void AddOverflowFromChildren() final; + void AddVisualOverflowFromChildren() final; + void AddLayoutOverflowFromChildren() final; private: void AddScrollingOverflowFromChildren();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc index 738e260..26afc91 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -576,7 +576,7 @@ physical_fragment); } - // |ComputeOverflow()| below calls |AddOverflowFromChildren()|, which + // |ComputeOverflow()| below calls |AddVisualOverflowFromChildren()|, which // computes visual overflow from |RootInlineBox| if |ChildrenInline()| block->ComputeOverflow(intrinsic_block_size - borders.block_end - scrollbars.block_end); @@ -592,8 +592,10 @@ LayoutBlockFlow* block_flow = ToLayoutBlockFlow(box_); block_flow->UpdateIsSelfCollapsing(); - if (constraint_space.IsNewFormattingContext()) - block_flow->AddOverflowFromFloats(); + if (constraint_space.IsNewFormattingContext()) { + block_flow->AddVisualOverflowFromFloats(); + block_flow->AddLayoutOverflowFromFloats(); + } } } @@ -617,8 +619,10 @@ CopyChildFragmentPosition(box_fragment, child_fragment.Offset(), offset_from_start); } - if (child_object->IsLayoutBlockFlow()) - ToLayoutBlockFlow(child_object)->AddOverflowFromFloats(); + if (child_object->IsLayoutBlockFlow()) { + ToLayoutBlockFlow(child_object)->AddVisualOverflowFromFloats(); + ToLayoutBlockFlow(child_object)->AddLayoutOverflowFromFloats(); + } } if (rendered_legend) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc index 140a787..b4c9d8f 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
@@ -248,10 +248,6 @@ .inline_size; } -NGFragmentationType NGConstraintSpace::BlockFragmentationType() const { - return static_cast<NGFragmentationType>(block_direction_fragmentation_type_); -} - bool NGConstraintSpace::operator==(const NGConstraintSpace& other) const { return available_size_ == other.available_size_ && percentage_resolution_size_ == other.percentage_resolution_size_ && @@ -280,10 +276,6 @@ baseline_requests_ == other.baseline_requests_; } -bool NGConstraintSpace::operator!=(const NGConstraintSpace& other) const { - return !(*this == other); -} - String NGConstraintSpace::ToString() const { return String::Format("Offset: %s,%s Size: %sx%s Clearance: %s", bfc_offset_.line_offset.ToString().Ascii().data(),
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h index 377b9de..f2caee8 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -184,7 +184,10 @@ // If specified a layout should produce a Fragment which fragments at the // blockSize if possible. - NGFragmentationType BlockFragmentationType() const; + NGFragmentationType BlockFragmentationType() const { + return static_cast<NGFragmentationType>( + block_direction_fragmentation_type_); + } // Return true if this constraint space participates in a fragmentation // context. @@ -278,7 +281,9 @@ } bool operator==(const NGConstraintSpace&) const; - bool operator!=(const NGConstraintSpace&) const; + bool operator!=(const NGConstraintSpace& other) const { + return !(*this == other); + } String ToString() const;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc index cf71646..6b9a510 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
@@ -8,24 +8,6 @@ namespace blink { -NGConstraintSpaceBuilder::NGConstraintSpaceBuilder( - const NGConstraintSpace& parent_space) - : NGConstraintSpaceBuilder(parent_space.GetWritingMode(), - parent_space.InitialContainingBlockSize()) { - parent_percentage_resolution_size_ = parent_space.PercentageResolutionSize(); - - flags_ = NGConstraintSpace::kFixedSizeBlockIsDefinite; - if (parent_space.IsIntermediateLayout()) - flags_ |= NGConstraintSpace::kIntermediateLayout; -} - -NGConstraintSpaceBuilder::NGConstraintSpaceBuilder(WritingMode writing_mode, - NGPhysicalSize icb_size) - : initial_containing_block_size_(icb_size), - parent_writing_mode_(writing_mode) { - flags_ = NGConstraintSpace::kFixedSizeBlockIsDefinite; -} - NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::AddBaselineRequest( const NGBaselineRequest& request) { for (const auto& existing : baseline_requests_) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h index e8ac08b..9cd328c 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -25,11 +25,23 @@ // NOTE: This constructor doesn't act like a copy-constructor, it uses the // writing_mode and icb_size from the parent constraint space, and passes // them to the constructor below. - NGConstraintSpaceBuilder(const NGConstraintSpace& parent_space); + NGConstraintSpaceBuilder(const NGConstraintSpace& parent_space) + : NGConstraintSpaceBuilder(parent_space.GetWritingMode(), + parent_space.InitialContainingBlockSize()) { + parent_percentage_resolution_size_ = + parent_space.PercentageResolutionSize(); + flags_ = NGConstraintSpace::kFixedSizeBlockIsDefinite; + if (parent_space.IsIntermediateLayout()) + flags_ |= NGConstraintSpace::kIntermediateLayout; + } // writing_mode is the writing mode that the logical sizes passed to the // setters are in. - NGConstraintSpaceBuilder(WritingMode writing_mode, NGPhysicalSize icb_size); + NGConstraintSpaceBuilder(WritingMode writing_mode, NGPhysicalSize icb_size) + : initial_containing_block_size_(icb_size), + parent_writing_mode_(writing_mode) { + flags_ = NGConstraintSpace::kFixedSizeBlockIsDefinite; + } NGConstraintSpaceBuilder& SetAvailableSize(NGLogicalSize available_size) { available_size_ = available_size;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc index 6c6250c4..cd7b3ea 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -36,7 +36,7 @@ LayoutUnit flex_container_content_inline_size = flex_container_content_box_size.inline_size; - FlexItemVector flex_items; + FlexLayoutAlgorithm algorithm(&Style(), flex_container_content_inline_size); for (NGLayoutInputNode generic_child = Node().FirstChild(); generic_child; generic_child = generic_child.NextSibling()) { NGBlockNode child = ToNGBlockNode(generic_child); @@ -94,15 +94,13 @@ // https://www.w3.org/TR/css-flexbox-1/#min-size-auto MinMaxSize min_max_sizes_in_main_axis_direction{LayoutUnit(), LayoutUnit::Max()}; - flex_items.emplace_back(child.GetLayoutBox(), flex_base_content_size, - min_max_sizes_in_main_axis_direction, - main_axis_border_and_padding, main_axis_margin); - flex_items.back().ng_input_node = child; + algorithm + .emplace_back(child.GetLayoutBox(), flex_base_content_size, + min_max_sizes_in_main_axis_direction, + main_axis_border_and_padding, main_axis_margin) + .ng_input_node = child; } - FlexLayoutAlgorithm algorithm(&Style(), flex_container_content_inline_size, - flex_items); - NGBoxStrut borders_scrollbar_padding = CalculateBorderScrollbarPadding(ConstraintSpace(), Node()); LayoutUnit main_axis_offset = borders_scrollbar_padding.inline_start;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.cc b/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.cc index 86a72b6e..66f347ea 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.cc
@@ -6,7 +6,6 @@ #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" -#include "third_party/blink/renderer/core/style/computed_style.h" namespace blink { @@ -18,16 +17,4 @@ NGUnpositionedFloat::~NGUnpositionedFloat() = default; -bool NGUnpositionedFloat::IsLeft() const { - return node.Style().Floating() == EFloat::kLeft; -} - -bool NGUnpositionedFloat::IsRight() const { - return node.Style().Floating() == EFloat::kRight; -} - -EClear NGUnpositionedFloat::ClearType() const { - return node.Style().Clear(); -} - } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h b/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h index b479a75..022e1d5 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h +++ b/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h
@@ -10,6 +10,7 @@ #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" +#include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/core/style/computed_style_constants.h" namespace blink { @@ -35,9 +36,9 @@ scoped_refptr<NGLayoutResult> layout_result; NGBoxStrut margins; - bool IsLeft() const; - bool IsRight() const; - EClear ClearType() const; + bool IsLeft() const { return node.Style().Floating() == EFloat::kLeft; } + bool IsRight() const { return node.Style().Floating() == EFloat::kRight; } + EClear ClearType() const { return node.Style().Clear(); } }; } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index b87a9a6..5f5effe7 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -444,6 +444,7 @@ state_ = kSentDidFinishLoad; GetLocalFrameClient().DispatchDidFailProvisionalLoad(error, history_commit_type); + probe::didFailProvisionalLoad(frame_); if (frame_) GetFrameLoader().DetachProvisionalDocumentLoader(this); break;
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc index c51ca2e..880ce05 100644 --- a/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -995,6 +995,7 @@ // the DidStartProvisionalLoad() notification. Client()->DispatchDidStartProvisionalLoad(provisional_document_loader_, resource_request); + probe::didStartProvisionalLoad(frame_); DCHECK(provisional_document_loader_); TakeObjectSnapshot(); } @@ -1088,6 +1089,7 @@ frame_->GetFrameScheduler()->DidStartProvisionalLoad(frame_->IsMainFrame()); Client()->DispatchDidStartProvisionalLoad(provisional_document_loader_, resource_request); + probe::didStartProvisionalLoad(frame_); provisional_document_loader_->StartLoading(); TakeObjectSnapshot();
diff --git a/third_party/blink/renderer/core/page/scrolling/snap_coordinator_test.cc b/third_party/blink/renderer/core/page/scrolling/snap_coordinator_test.cc index 119f7ba3..254d079 100644 --- a/third_party/blink/renderer/core/page/scrolling/snap_coordinator_test.cc +++ b/third_party/blink/renderer/core/page/scrolling/snap_coordinator_test.cc
@@ -620,10 +620,10 @@ ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory), gfx::RectF(10, 10, width - 20, height - 20), gfx::ScrollOffset(max_position.X(), max_position.Y())); - // Under vertical-rl writing mode, 'start' should align to the right, so the - // alignment on x should be reversed. + // Under vertical-rl writing mode, 'start' should align to the right + // and 'end' should align to the left. SnapAreaData expected_area( - ScrollSnapAlign(SnapAlignment::kEnd, SnapAlignment::kStart), + ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kEnd), gfx::RectF(192, 192, 116, 116), false); expected_container.AddSnapAreaData(expected_area);
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc index f44b711..967b42f 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -955,7 +955,7 @@ ->GetFrame() ->GetPage() ->GetVisualViewport() - .SetNeedsPaintPropertiesUpdate(); + .SetNeedsPaintPropertyUpdate(); } }
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc index f02567d..5fd0b75 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -316,6 +316,13 @@ return object.HasLayer() && object.ShouldApplyPaintContainment(); } +static bool NeedsStickyTranslation(const LayoutObject& object) { + if (!object.IsBoxModelObject()) + return false; + + return object.StyleRef().HasStickyConstrainedPosition(); +} + static bool NeedsPaintOffsetTranslation(const LayoutObject& object) { if (!object.IsBoxModelObject()) return false; @@ -349,6 +356,8 @@ } if (NeedsScrollOrScrollTranslation(object)) return true; + if (NeedsStickyTranslation(object)) + return true; if (NeedsPaintOffsetTranslationForScrollbars(box_model)) return true; if (NeedsReplacedContentTransform(object)) @@ -435,13 +444,6 @@ } } -static bool NeedsStickyTranslation(const LayoutObject& object) { - if (!object.IsBoxModelObject()) - return false; - - return object.StyleRef().HasStickyConstrainedPosition(); -} - void FragmentPaintPropertyTreeBuilder::UpdateStickyTranslation() { DCHECK(properties_); @@ -709,9 +711,6 @@ return false; if (object.IsSVG()) { - if (object.IsSVGRoot() && is_css_isolated_group && - object.HasNonIsolatedBlendingDescendants()) - return true; if (SVGLayoutSupport::IsIsolationRequired(&object)) return true; if (SVGResources* resources = @@ -720,11 +719,31 @@ return true; } } - } else if (object.IsBoxModelObject()) { - if (PaintLayer* layer = ToLayoutBoxModelObject(object).Layer()) { - if (layer->HasNonIsolatedDescendantWithBlendMode()) - return true; - } + } + + if (is_css_isolated_group) { + if (object.IsSVGRoot() && object.HasNonIsolatedBlendingDescendants()) + return true; + + const auto* layer = ToLayoutBoxModelObject(object).Layer(); + DCHECK(layer); + + if (layer->HasNonIsolatedDescendantWithBlendMode()) + return true; + + // In SPv1* a mask layer can be created for clip-path in absence of mask, + // and a mask effect node must be created whether the clip-path is + // path-based or not. + if (layer->GetCompositedLayerMapping() && + layer->GetCompositedLayerMapping()->MaskLayer()) + return true; + + // An effect node is required by cc if the layer flattens its subtree but it + // is treated as a 3D object by its parent. + if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() && + !layer->Preserves3D() && layer->HasSelfPaintingLayerDescendant() && + layer->Parent() && layer->Parent()->Preserves3D()) + return true; } SkBlendMode blend_mode = object.IsBlendingAllowed() @@ -743,18 +762,6 @@ if (object.StyleRef().HasMask()) return true; - if (object.HasLayer() && - ToLayoutBoxModelObject(object).Layer()->GetCompositedLayerMapping() && - ToLayoutBoxModelObject(object) - .Layer() - ->GetCompositedLayerMapping() - ->MaskLayer()) { - // In SPv1* a mask layer can be created for clip-path in absence of mask, - // and a mask effect node must be created whether the clip-path is - // path-based or not. - return true; - } - if (object.StyleRef().ClipPath() && object.FirstFragment().ClipPathBoundingBox() && !object.FirstFragment().ClipPathPath()) { @@ -763,16 +770,6 @@ return true; } - // An effect node is required by cc if the layer flattens its subtree but it - // is treated as a 3D object by its parent. - if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() && - object.HasLayer()) { - PaintLayer* layer = ToLayoutBoxModelObject(object).Layer(); - if (!layer->Preserves3D() && layer->HasSelfPaintingLayerDescendant() && - layer->Parent() && layer->Parent()->Preserves3D()) - return true; - } - return false; } @@ -814,7 +811,6 @@ DCHECK(properties_); const ComputedStyle& style = object_.StyleRef(); - // TODO(trchen): Can't omit effect node if we have 3D children. if (NeedsPaintPropertyUpdate()) { if (NeedsEffect(object_)) { base::Optional<IntRect> mask_clip = CSSMaskPainter::MaskBoundingBox(
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc index 897ac7f..d8b04e0 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -6390,4 +6390,78 @@ EXPECT_EQ(nullptr, PaintPropertiesForElement("col")); } +TEST_P(PaintPropertyTreeBuilderTest, SVGRootCompositedClipPath) { + SetBodyInnerHTML(R"HTML( + <svg id='svg' style='clip-path: circle(); will-change: transform'></svg> + )HTML"); + + const auto* properties = PaintPropertiesForElement("svg"); + + ASSERT_NE(nullptr, properties->PaintOffsetTranslation()); + const auto* transform = properties->Transform(); + ASSERT_NE(nullptr, transform); + EXPECT_EQ(properties->PaintOffsetTranslation(), transform->Parent()); + if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() || + RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) + EXPECT_TRUE(transform->HasDirectCompositingReasons()); + + if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) { + EXPECT_EQ(nullptr, properties->MaskClip()); + + const auto* clip_path_clip = properties->ClipPathClip(); + ASSERT_NE(nullptr, clip_path_clip); + EXPECT_EQ(DocContentClip(), clip_path_clip->Parent()); + EXPECT_EQ(FloatRect(75, 0, 150, 150), clip_path_clip->ClipRect().Rect()); + EXPECT_EQ(transform, clip_path_clip->LocalTransformSpace()); + EXPECT_NE(nullptr, clip_path_clip->ClipPath()); + + const auto* overflow_clip = properties->OverflowClip(); + ASSERT_NE(nullptr, overflow_clip); + EXPECT_EQ(clip_path_clip, overflow_clip->Parent()); + EXPECT_EQ(FloatRect(0, 0, 300, 150), overflow_clip->ClipRect().Rect()); + EXPECT_EQ(transform, overflow_clip->LocalTransformSpace()); + + // TODO(wangxianzhu): Are the following correct? + EXPECT_EQ(nullptr, properties->Effect()); + EXPECT_EQ(nullptr, properties->Mask()); + EXPECT_EQ(nullptr, properties->ClipPath()); + } else { + const auto* mask_clip = properties->MaskClip(); + ASSERT_NE(nullptr, mask_clip); + EXPECT_EQ(DocContentClip(), mask_clip->Parent()); + EXPECT_EQ(FloatRect(75, 0, 150, 150), mask_clip->ClipRect().Rect()); + EXPECT_EQ(nullptr, mask_clip->ClipPath()); + EXPECT_EQ(transform, mask_clip->LocalTransformSpace()); + + const auto* clip_path_clip = properties->ClipPathClip(); + ASSERT_NE(nullptr, clip_path_clip); + EXPECT_EQ(mask_clip, clip_path_clip->Parent()); + EXPECT_EQ(FloatRect(75, 0, 150, 150), clip_path_clip->ClipRect().Rect()); + EXPECT_EQ(transform, clip_path_clip->LocalTransformSpace()); + EXPECT_NE(nullptr, clip_path_clip->ClipPath()); + + const auto* overflow_clip = properties->OverflowClip(); + ASSERT_NE(nullptr, overflow_clip); + EXPECT_EQ(mask_clip, overflow_clip->Parent()); + EXPECT_EQ(FloatRect(0, 0, 300, 150), overflow_clip->ClipRect().Rect()); + EXPECT_EQ(transform, overflow_clip->LocalTransformSpace()); + + const auto* effect = properties->Effect(); + ASSERT_NE(nullptr, effect); + EXPECT_EQ(&EffectPaintPropertyNode::Root(), effect->Parent()); + EXPECT_EQ(transform, effect->LocalTransformSpace()); + EXPECT_EQ(mask_clip, effect->OutputClip()); + EXPECT_EQ(SkBlendMode::kSrcOver, effect->BlendMode()); + + const auto* mask = properties->Mask(); + ASSERT_NE(nullptr, mask); + EXPECT_EQ(effect, mask->Parent()); + EXPECT_EQ(transform, mask->LocalTransformSpace()); + EXPECT_EQ(mask_clip, mask->OutputClip()); + EXPECT_EQ(SkBlendMode::kDstIn, mask->BlendMode()); + + EXPECT_EQ(nullptr, properties->ClipPath()); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc index b5389d8..4833959 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/paint/paint_property_tree_builder_test.h" #include "third_party/blink/renderer/core/paint/paint_property_tree_printer.h" +#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h" namespace blink { @@ -1367,4 +1368,54 @@ EXPECT_EQ(nullptr, effect_properties->Effect()->OutputClip()); } +TEST_P(PaintPropertyTreeUpdateTest, ForwardReferencedSVGElementUpdate) { + SetBodyInnerHTML(R"HTML( + <svg id="svg1" filter="url(#filter)"> + <filter id="filter"> + <feImage id="image" href="#rect"/> + </filter> + </svg> + <svg id="svg2" style="perspective: 10px"> + <rect id="rect" width="100" height="100" transform="translate(1)"/> + </svg> + )HTML"); + + const auto* svg2_properties = PaintPropertiesForElement("svg2"); + EXPECT_NE(nullptr, svg2_properties->PaintOffsetTranslation()); + EXPECT_EQ(nullptr, svg2_properties->Transform()); + EXPECT_NE(nullptr, svg2_properties->Perspective()); + EXPECT_EQ(svg2_properties->PaintOffsetTranslation(), + svg2_properties->Perspective()->Parent()); + + const auto* rect_properties = PaintPropertiesForElement("rect"); + ASSERT_NE(nullptr, rect_properties->Transform()); + EXPECT_EQ(svg2_properties->Perspective(), + rect_properties->Transform()->Parent()); + EXPECT_EQ(TransformationMatrix().Translate(1, 0), + GeometryMapper::SourceToDestinationProjection( + rect_properties->Transform(), + svg2_properties->PaintOffsetTranslation())); + + // Change filter which forward references rect, and insert a transform + // node above rect's transform. + GetDocument().getElementById("filter")->setAttribute("width", "20"); + GetDocument().getElementById("svg2")->setAttribute("transform", + "translate(2)"); + UpdateAllLifecyclePhases(); + + EXPECT_NE(nullptr, svg2_properties->Transform()); + EXPECT_EQ(svg2_properties->PaintOffsetTranslation(), + svg2_properties->Transform()->Parent()); + EXPECT_EQ(svg2_properties->Transform(), + svg2_properties->Perspective()->Parent()); + EXPECT_EQ(svg2_properties->Perspective(), + rect_properties->Transform()->Parent()); + + // Ensure that GeometryMapper's cache is properly invalidated and updated. + EXPECT_EQ(TransformationMatrix().Translate(3, 0), + GeometryMapper::SourceToDestinationProjection( + rect_properties->Transform(), + svg2_properties->PaintOffsetTranslation())); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc index 07b8080..35a7b782 100644 --- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc +++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/frame/visual_viewport.h" #include "third_party/blink/renderer/core/layout/jank_tracker.h" #include "third_party/blink/renderer/core/layout/layout_embedded_content.h" #include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h" @@ -271,6 +272,12 @@ bool PrePaintTreeWalk::NeedsTreeBuilderContextUpdate( const LocalFrameView& frame_view, const PrePaintTreeWalkContext& context) { + if ((RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() || + RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) && + frame_view.GetFrame().IsLocalRoot() && + frame_view.GetPage()->GetVisualViewport().NeedsPaintPropertyUpdate()) + return true; + return frame_view.GetLayoutView() && NeedsTreeBuilderContextUpdate(*frame_view.GetLayoutView(), context); }
diff --git a/third_party/blink/renderer/core/probe/core_probes.json5 b/third_party/blink/renderer/core/probe/core_probes.json5 index 069fb23f..ef19904db 100644 --- a/third_party/blink/renderer/core/probe/core_probes.json5 +++ b/third_party/blink/renderer/core/probe/core_probes.json5
@@ -215,5 +215,11 @@ "workerTerminated", ] }, + InspectorSession: { + probes: [ + "didStartProvisionalLoad", + "didFailProvisionalLoad", + ] + }, } }
diff --git a/third_party/blink/renderer/core/probe/core_probes.pidl b/third_party/blink/renderer/core/probe/core_probes.pidl index 09d3ee88..11322da0 100644 --- a/third_party/blink/renderer/core/probe/core_probes.pidl +++ b/third_party/blink/renderer/core/probe/core_probes.pidl
@@ -111,6 +111,8 @@ void loadEventFired([Keep] LocalFrame*); void frameAttachedToParent([Keep] LocalFrame*); void frameDetachedFromParent([Keep] LocalFrame*); + void didStartProvisionalLoad([Keep] LocalFrame*); + void didFailProvisionalLoad([Keep] LocalFrame*); void willCommitLoad([Keep] LocalFrame*, DocumentLoader*); void didCommitLoad([Keep] LocalFrame*, DocumentLoader*); void didNavigateWithinDocument([Keep] LocalFrame*);
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsolePinPane.js b/third_party/blink/renderer/devtools/front_end/console/ConsolePinPane.js index d1cdc0a..0ca624e 100644 --- a/third_party/blink/renderer/devtools/front_end/console/ConsolePinPane.js +++ b/third_party/blink/renderer/devtools/front_end/console/ConsolePinPane.js
@@ -17,6 +17,14 @@ this.addPin(expression); } + /** + * @override + */ + willHide() { + for (const pin of this._pins) + pin.setHovered(false); + } + _savePins() { const toSave = Array.from(this._pins).map(pin => pin.expression()); this._pinsSetting.set(toSave); @@ -114,6 +122,18 @@ /** @type {?UI.TextEditor} */ this._editor = null; this._committedExpression = expression; + this._hovered = false; + /** @type {?SDK.RemoteObject} */ + this._lastNode = null; + + this._pinPreview.addEventListener('mouseenter', this.setHovered.bind(this, true), false); + this._pinPreview.addEventListener('mouseleave', this.setHovered.bind(this, false), false); + this._pinPreview.addEventListener('click', event => { + if (this._lastNode) { + Common.Revealer.reveal(this._lastNode); + event.consume(); + } + }, false); this._editorPromise = self.runtime.extension(UI.TextEditorFactory).instance().then(factory => { this._editor = factory.createEditor({ @@ -148,6 +168,17 @@ } /** + * @param {boolean} hovered + */ + setHovered(hovered) { + if (this._hovered === hovered) + return; + this._hovered = hovered; + if (!hovered && this._lastNode) + SDK.OverlayModel.hideDOMNodeHighlight(); + } + + /** * @return {string} */ expression() { @@ -171,8 +202,11 @@ * @param {!UI.ContextMenu} contextMenu */ appendToContextMenu(contextMenu) { - if (this._lastResult && this._lastResult.object) + if (this._lastResult && this._lastResult.object) { contextMenu.appendApplicableItems(this._lastResult.object); + // Prevent result from being released manually. It will release along with 'console' group. + this._lastResult = null; + } } /** @@ -187,10 +221,11 @@ const timeout = throwOnSideEffect ? 250 : undefined; this._lastExecutionContext = UI.context.flavor(SDK.ExecutionContext); const {preview, result} = await ObjectUI.JavaScriptREPL.evaluateAndBuildPreview( - text, throwOnSideEffect, timeout, !isEditing /* allowErrors */); + text, throwOnSideEffect, timeout, !isEditing /* allowErrors */, 'console'); if (this._lastResult) this._lastExecutionContext.runtimeModel.releaseEvaluationResult(this._lastResult); this._lastResult = result || null; + const previewText = preview.deepTextContent(); if (!previewText || previewText !== this._pinPreview.deepTextContent()) { this._pinPreview.removeChildren(); @@ -206,6 +241,17 @@ this._pinPreview.title = previewText; } + let node = null; + if (result && result.object && result.object.type === 'object' && result.object.subtype === 'node') + node = result.object; + if (this._hovered) { + if (node) + SDK.OverlayModel.highlightObjectAsDOMNode(node); + else if (this._lastNode) + SDK.OverlayModel.hideDOMNodeHighlight(); + } + this._lastNode = node || null; + const isError = result && result.exceptionDetails && !SDK.RuntimeModel.isSideEffectFailure(result); this._pinElement.classList.toggle('error-level', isError); }
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js index 22236b1..7ab961e 100644 --- a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js +++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
@@ -45,6 +45,8 @@ this._repeatCount = 1; this._closeGroupDecorationCount = 0; this._nestingLevel = nestingLevel; + /** @type {!Array<!ObjectUI.ObjectPropertiesSection>} */ + this._focusableChildren = []; /** @type {?DataGrid.DataGrid} */ this._dataGrid = null; @@ -608,6 +610,7 @@ const section = new ObjectUI.ObjectPropertiesSection(obj, titleElement, this._linkifier); section.element.classList.add('console-view-object-properties-section'); section.enableContextMenu(); + this._focusableChildren.push(section); return section.element; } @@ -1035,6 +1038,15 @@ } /** + * @return {number} + */ + _focusedChildIndex() { + if (!this._focusableChildren.length) + return -1; + return this._focusableChildren.findIndex(child => child.element.hasFocus()); + } + + /** * @param {!Event} event */ _onKeyDown(event) { @@ -1050,16 +1062,66 @@ */ maybeHandleOnKeyDown(event) { // Handle trace expansion. - if (this._expandTrace) { + const focusedChildIndex = this._focusedChildIndex(); + const isWrapperFocused = focusedChildIndex === -1; + if (this._expandTrace && isWrapperFocused) { if ((event.key === 'ArrowLeft' && this._traceExpanded) || (event.key === 'ArrowRight' && !this._traceExpanded)) { this._expandTrace(!this._traceExpanded); return true; } } + if (!this._focusableChildren.length) + return false; + + if (event.key === 'ArrowLeft') { + this._element.focus(); + return true; + } + if (event.key === 'ArrowRight') { + if (isWrapperFocused) { + this._focusChild(0); + return true; + } + } + if (event.key === 'ArrowUp') { + if (focusedChildIndex === 0) { + this._element.focus(); + return true; + } else if (focusedChildIndex > 0) { + this._focusChild(focusedChildIndex - 1); + return true; + } + } + if (event.key === 'ArrowDown') { + if (isWrapperFocused) { + this._focusChild(0); + return true; + } else if (focusedChildIndex < this._focusableChildren.length - 1) { + this._focusChild(focusedChildIndex + 1); + return true; + } + } return false; } /** + * @param {number} index + */ + _focusChild(index) { + const section = this._focusableChildren[index]; + if (!section.objectTreeElement().selected) + section.objectTreeElement().select(); + section.focus(); + } + + focusLastChildOrSelf() { + if (this._focusableChildren.length) + this._focusChild(this._focusableChildren.length - 1); + else if (this._element) + this._element.focus(); + } + + /** * @return {!Element} */ contentElement() { @@ -1557,9 +1619,12 @@ * @param {!Event} event */ maybeHandleOnKeyDown(event) { - if ((event.key === 'ArrowLeft' && !this._collapsed) || (event.key === 'ArrowRight' && this._collapsed)) { - this._setCollapsed(!this._collapsed); - return true; + const focusedChildIndex = this._focusedChildIndex(); + if (focusedChildIndex === -1) { + if ((event.key === 'ArrowLeft' && !this._collapsed) || (event.key === 'ArrowRight' && this._collapsed)) { + this._setCollapsed(!this._collapsed); + return true; + } } return super.maybeHandleOnKeyDown(event); }
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js index d0378a0..f1ea217 100644 --- a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js +++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js
@@ -171,16 +171,21 @@ _onKeyDown(event) { if (UI.isEditing() || !this._itemCount || event.shiftKey) return; + let isArrowUp = false; switch (event.key) { case 'ArrowUp': - this._virtualSelectedIndex--; - if (this._virtualSelectedIndex < 0) - this._virtualSelectedIndex = this._itemCount - 1; + if (this._virtualSelectedIndex > 0) { + isArrowUp = true; + this._virtualSelectedIndex--; + } else { + return; + } break; case 'ArrowDown': - this._virtualSelectedIndex++; - if (this._virtualSelectedIndex >= this._itemCount) - this._virtualSelectedIndex = 0; + if (this._virtualSelectedIndex < this._itemCount - 1) + this._virtualSelectedIndex++; + else + return; break; case 'Home': this._virtualSelectedIndex = 0; @@ -193,20 +198,27 @@ } event.consume(true); this.scrollItemIntoView(this._virtualSelectedIndex); - this._updateFocusedItem(); + this._updateFocusedItem(isArrowUp); } - _updateFocusedItem() { + /** + * @param {boolean=} focusLastChild + */ + _updateFocusedItem(focusLastChild) { const selectedElement = this.renderedElementAt(this._virtualSelectedIndex); const changed = this._lastSelectedElement !== selectedElement; const containerHasFocus = this._contentElement === this.element.ownerDocument.deepActiveElement(); if (this._lastSelectedElement && changed) this._lastSelectedElement.classList.remove('console-selected'); - if (selectedElement && (changed || containerHasFocus)) { + if (selectedElement && (changed || containerHasFocus) && this.element.hasFocus()) { selectedElement.classList.add('console-selected'); // Do not focus the message if something within holds focus (e.g. object). - if (!selectedElement.hasFocus()) - focusWithoutScroll(selectedElement); + if (!selectedElement.hasFocus()) { + if (focusLastChild) + this._renderedItems[this._virtualSelectedIndex - this._firstActiveIndex].focusLastChildOrSelf(); + else + focusWithoutScroll(selectedElement); + } } if (this._itemCount && !this._contentElement.hasFocus()) this._contentElement.tabIndex = 0;
diff --git a/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js b/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js index dc28c73c..aea6002 100644 --- a/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js +++ b/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js
@@ -444,6 +444,13 @@ /** * @return {!Promise} */ +ConsoleTestRunner.waitForRemoteObjectsConsoleMessagesPromise = function() { + return new Promise(resolve => ConsoleTestRunner.waitForRemoteObjectsConsoleMessages(resolve)); +}; + +/** + * @return {!Promise} + */ ConsoleTestRunner.waitUntilConsoleEditorLoaded = function() { let fulfill; const promise = new Promise(x => (fulfill = x));
diff --git a/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptREPL.js b/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptREPL.js index bdec0d7..f0b73e6 100644 --- a/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptREPL.js +++ b/third_party/blink/renderer/devtools/front_end/object_ui/JavaScriptREPL.js
@@ -47,9 +47,10 @@ * @param {boolean} throwOnSideEffect * @param {number=} timeout * @param {boolean=} allowErrors + * @param {string=} objectGroup * @return {!Promise<!{preview: !DocumentFragment, result: ?SDK.RuntimeModel.EvaluationResult}>} */ - static async evaluateAndBuildPreview(text, throwOnSideEffect, timeout, allowErrors) { + static async evaluateAndBuildPreview(text, throwOnSideEffect, timeout, allowErrors, objectGroup) { const executionContext = UI.context.flavor(SDK.ExecutionContext); const isTextLong = text.length > ObjectUI.JavaScriptREPL._MaxLengthForEvaluation; if (!text || !executionContext || (throwOnSideEffect && isTextLong)) @@ -61,7 +62,8 @@ generatePreview: true, includeCommandLineAPI: true, throwOnSideEffect: throwOnSideEffect, - timeout: timeout + timeout: timeout, + objectGroup: objectGroup }; const result = await executionContext.evaluate( options, false /* userGesture */, wrappedResult.preprocessed /* awaitPromise */);
diff --git a/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl b/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl index 8e50e6f..d1df3325 100644 --- a/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl +++ b/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl
@@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#enumdef-choosefilesystementriestype enum ChooseFileSystemEntriesType { "openFile", "saveFile", "openDirectory" }; +// https://wicg.github.io/writable-files/#dictdef-choosefilesystementriesoptions dictionary ChooseFileSystemEntriesOptions { ChooseFileSystemEntriesType type = "openFile"; boolean multiple = false;
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_base_handle.idl b/third_party/blink/renderer/modules/filesystem/file_system_base_handle.idl index 0899593..20008ad4 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_base_handle.idl +++ b/third_party/blink/renderer/modules/filesystem/file_system_base_handle.idl
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#filesystemhandle [ RuntimeEnabled=WritableFiles, NoInterfaceObject
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.idl b/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.idl index 4475c46..5e2309e 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.idl +++ b/third_party/blink/renderer/modules/filesystem/file_system_directory_handle.idl
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#filesystemdirectoryhandle [ RuntimeEnabled=WritableFiles ] interface FileSystemDirectoryHandle : FileSystemBaseHandle {
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_file_handle.idl b/third_party/blink/renderer/modules/filesystem/file_system_file_handle.idl index 7b554909..74f5582 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_file_handle.idl +++ b/third_party/blink/renderer/modules/filesystem/file_system_file_handle.idl
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#filesystemfilehandle [ RuntimeEnabled=WritableFiles ] interface FileSystemFileHandle : FileSystemBaseHandle {
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_get_directory_options.idl b/third_party/blink/renderer/modules/filesystem/file_system_get_directory_options.idl index b430b67..246e8108 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_get_directory_options.idl +++ b/third_party/blink/renderer/modules/filesystem/file_system_get_directory_options.idl
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#dictdef-filesystemgetdirectoryoptions dictionary FileSystemGetDirectoryOptions { boolean create = false; };
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_get_file_options.idl b/third_party/blink/renderer/modules/filesystem/file_system_get_file_options.idl index ec0f2d24..19c7978f 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_get_file_options.idl +++ b/third_party/blink/renderer/modules/filesystem/file_system_get_file_options.idl
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#dictdef-filesystemgetfileoptions dictionary FileSystemGetFileOptions { boolean create = false; };
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_writer.idl b/third_party/blink/renderer/modules/filesystem/file_system_writer.idl index b3e225cb..b1cf941 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_writer.idl +++ b/third_party/blink/renderer/modules/filesystem/file_system_writer.idl
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#filesystemwriter [ NoInterfaceObject, RuntimeEnabled=WritableFiles
diff --git a/third_party/blink/renderer/modules/filesystem/get_system_directory_options.idl b/third_party/blink/renderer/modules/filesystem/get_system_directory_options.idl index 319adbc..831ac356 100644 --- a/third_party/blink/renderer/modules/filesystem/get_system_directory_options.idl +++ b/third_party/blink/renderer/modules/filesystem/get_system_directory_options.idl
@@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +// https://wicg.github.io/writable-files/#enumdef-systemdirectorytype enum SystemDirectoryType { "sandbox" }; +// https://wicg.github.io/writable-files/#dictdef-getsystemdirectoryoptions dictionary GetSystemDirectoryOptions { required SystemDirectoryType type; };
diff --git a/third_party/blink/renderer/modules/filesystem/window_file_system.idl b/third_party/blink/renderer/modules/filesystem/window_file_system.idl index ed10797d..935f48bc 100644 --- a/third_party/blink/renderer/modules/filesystem/window_file_system.idl +++ b/third_party/blink/renderer/modules/filesystem/window_file_system.idl
@@ -38,8 +38,7 @@ [RuntimeEnabled=FileSystem] void webkitResolveLocalFileSystemURL(DOMString url, EntryCallback successCallback, optional ErrorCallback? errorCallback); - // https://github.com/WICG/writable-files/blob/master/EXPLAINER.md - // TODO(crbug.com/878581): This needs some kind of options dictionary. + // https://wicg.github.io/writable-files/#api-choosefilesystementries [RuntimeEnabled=WritableFiles, CallWith=ScriptState, SecureContext] Promise<(FileSystemBaseHandle or sequence<FileSystemBaseHandle>)> chooseFileSystemEntries(optional ChooseFileSystemEntriesOptions options);
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc index cc6c9eac..9e05d3b 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -538,8 +538,7 @@ overlay_enclosure_ = new MediaControlOverlayEnclosureElement(*this); - if (RuntimeEnabledFeatures::MediaControlsOverlayPlayButtonEnabled() || - IsModern()) { + if (RuntimeEnabledFeatures::MediaControlsOverlayPlayButtonEnabled()) { overlay_play_button_ = new MediaControlOverlayPlayButtonElement(*this); if (!IsModern()) @@ -650,7 +649,7 @@ if (display_cutout_fullscreen_button_) panel_->ParserAppendChild(display_cutout_fullscreen_button_); - panel_->ParserAppendChild(overlay_play_button_); + MaybeParserAppendChild(panel_, overlay_play_button_); panel_->ParserAppendChild(media_button_panel_); button_panel = media_button_panel_; } @@ -770,18 +769,35 @@ // If we are in the "no-source" state we should show the overflow menu on a // video element. if (IsModern()) { + bool updated = false; + if (state == kNoSource) { - // Check if the overflow menu has the "disabled" attribute set so we avoid - // unnecessarily resetting it. + // Check if the play button or overflow menu has the "disabled" attribute + // set so we avoid unnecessarily resetting it. + if (!play_button_->hasAttribute(HTMLNames::disabledAttr)) { + play_button_->setAttribute(HTMLNames::disabledAttr, ""); + updated = true; + } + if (ShouldShowVideoControls() && !overflow_menu_->hasAttribute(HTMLNames::disabledAttr)) { overflow_menu_->setAttribute(HTMLNames::disabledAttr, ""); - UpdateOverflowMenuWanted(); + updated = true; } - } else if (overflow_menu_->hasAttribute(HTMLNames::disabledAttr)) { - overflow_menu_->removeAttribute(HTMLNames::disabledAttr); - UpdateOverflowMenuWanted(); + } else { + if (play_button_->hasAttribute(HTMLNames::disabledAttr)) { + play_button_->removeAttribute(HTMLNames::disabledAttr); + updated = true; + } + + if (overflow_menu_->hasAttribute(HTMLNames::disabledAttr)) { + overflow_menu_->removeAttribute(HTMLNames::disabledAttr); + updated = true; + } } + + if (updated) + UpdateOverflowMenuWanted(); } } @@ -1265,13 +1281,16 @@ // room and hide the overlay play button if there is not enough room. if (ShouldShowVideoControls()) { // Allocate vertical room for overlay play button if necessary. - WebSize overlay_play_button_size = overlay_play_button_->GetSizeOrDefault(); - if (controls_size.height >= overlay_play_button_size.height && - controls_size.width >= kModernMinWidthForOverlayPlayButton) { - overlay_play_button_->SetDoesFit(true); - controls_size.height -= overlay_play_button_size.height; - } else { - overlay_play_button_->SetDoesFit(false); + if (overlay_play_button_) { + WebSize overlay_play_button_size = + overlay_play_button_->GetSizeOrDefault(); + if (controls_size.height >= overlay_play_button_size.height && + controls_size.width >= kModernMinWidthForOverlayPlayButton) { + overlay_play_button_->SetDoesFit(true); + controls_size.height -= overlay_play_button_size.height; + } else { + overlay_play_button_->SetDoesFit(false); + } } controls_size.width -= kModernControlsVideoButtonPadding; @@ -1288,7 +1307,8 @@ } // If we cannot show the overlay play button, show the normal one. - play_button_->SetIsWanted(!overlay_play_button_->DoesFit()); + play_button_->SetIsWanted(!overlay_play_button_ || + !overlay_play_button_->DoesFit()); } else { controls_size.width -= kModernControlsAudioButtonPadding; @@ -1509,7 +1529,7 @@ !IsSpatialNavigationEnabled(GetDocument().GetFrame())) { const String& key = ToKeyboardEvent(event).key(); if (key == "Enter" || ToKeyboardEvent(event).keyCode() == ' ') { - if (IsModern()) { + if (IsModern() && overlay_play_button_) { overlay_play_button_->OnMediaKeyboardEvent(&event); } else { play_button_->OnMediaKeyboardEvent(&event);
diff --git a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css index 0008b69..7f114af 100644 --- a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css +++ b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
@@ -243,20 +243,20 @@ video::-webkit-media-controls.sizing-small div[pseudo="-internal-media-controls-button-panel" i] { height: 48px; - line-height: 44px; + line-height: 48px; padding: 0 0 0 16px; } video::-webkit-media-controls.sizing-medium div[pseudo="-internal-media-controls-button-panel" i] { height: 64px; - line-height: 60px; + line-height: 64px; padding: 0 16px 0 32px; } /* TODO(https://crbug.com/857120): remove these rules and the sizing-large CSS class. */ video::-webkit-media-controls.sizing-large div[pseudo="-internal-media-controls-button-panel" i] { height: 64px; - line-height: 60px; + line-height: 64px; padding: 0 16px 0 32px; } @@ -309,8 +309,10 @@ } audio::-webkit-media-controls-mute-button:disabled, +audio::-webkit-media-controls-play-button:disabled, video::-internal-media-controls-overflow-button:disabled, video::-webkit-media-controls-mute-button:disabled, +video::-webkit-media-controls-play-button:disabled, video::-webkit-media-controls-fullscreen-button:disabled { background-color: initial; opacity: 0.3; @@ -424,6 +426,13 @@ background-image: -webkit-image-set(url(ic_pause_white.svg) 1x); } +video::-webkit-media-controls:not(.audio-only) input[pseudo="-webkit-media-controls-play-button"] { + /* Undo the extra 16px of left padding on the button panel. We only want that + * extra padding when the current time is the leftmost item, and not when the + * play button is leftmost. */ + margin-left: -16px; +} + /** * Timeline */
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 777db98..8c0b114 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -804,6 +804,7 @@ "graphics/animation_worklet_mutator_dispatcher_impl.cc", "graphics/animation_worklet_mutator_dispatcher_impl.h", "graphics/animation_worklet_mutators_state.h", + "graphics/apply_viewport_changes.h", "graphics/begin_frame_provider.cc", "graphics/begin_frame_provider.h", "graphics/bitmap_image.cc",
diff --git a/third_party/blink/renderer/platform/graphics/apply_viewport_changes.h b/third_party/blink/renderer/platform/graphics/apply_viewport_changes.h new file mode 100644 index 0000000..c51a13b --- /dev/null +++ b/third_party/blink/renderer/platform/graphics/apply_viewport_changes.h
@@ -0,0 +1,18 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_APPLY_VIEWPORT_CHANGES_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_APPLY_VIEWPORT_CHANGES_H_ + +#include "cc/trees/layer_tree_host_client.h" + +namespace blink { + +// Allow us to use the Args struct for ApplyViewportChanges method within Blink +// core. +using ApplyViewportChangesArgs = cc::ApplyViewportChangesArgs; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_APPLY_VIEWPORT_CHANGES_H_
diff --git a/third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.cc b/third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.cc index e7bd01d..9ee3a58e 100644 --- a/third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.cc +++ b/third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.cc
@@ -60,8 +60,8 @@ size_t ClipPaintPropertyNode::CacheMemoryUsageInBytes() const { size_t total_bytes = sizeof(*this); - if (geometry_mapper_clip_cache_) - total_bytes += sizeof(*geometry_mapper_clip_cache_); + if (clip_cache_) + total_bytes += sizeof(*clip_cache_); if (Parent()) total_bytes += Parent()->CacheMemoryUsageInBytes(); return total_bytes;
diff --git a/third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.h b/third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.h index 16fe0724..503c83d 100644 --- a/third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.h +++ b/third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.h
@@ -76,8 +76,8 @@ return parent_changed; DCHECK(!IsParentAlias()) << "Changed the state of an alias node."; - SetChanged(); state_ = std::move(state); + SetChanged(); return true; } @@ -129,11 +129,24 @@ size_t CacheMemoryUsageInBytes() const; private: + friend class PaintPropertyNode<ClipPaintPropertyNode>; + ClipPaintPropertyNode(const ClipPaintPropertyNode* parent, State&& state, bool is_parent_alias) : PaintPropertyNode(parent, is_parent_alias), state_(std::move(state)) {} + void SetChanged() { + // TODO(crbug.com/814815): This is a workaround of the bug. When the bug is + // fixed, change the following condition to + // DCHECK(!clip_cache_ || !clip_cache_->IsValid()); + if (clip_cache_ && clip_cache_->IsValid()) { + DLOG(WARNING) << "Clip tree changed without invalidating the cache."; + GeometryMapperClipCache::ClearCache(); + } + PaintPropertyNode::SetChanged(); + } + // For access to GetClipCache(); friend class GeometryMapper; friend class GeometryMapperTest; @@ -143,13 +156,13 @@ } GeometryMapperClipCache& GetClipCache() { - if (!geometry_mapper_clip_cache_) - geometry_mapper_clip_cache_.reset(new GeometryMapperClipCache()); - return *geometry_mapper_clip_cache_.get(); + if (!clip_cache_) + clip_cache_.reset(new GeometryMapperClipCache()); + return *clip_cache_.get(); } State state_; - std::unique_ptr<GeometryMapperClipCache> geometry_mapper_clip_cache_; + std::unique_ptr<GeometryMapperClipCache> clip_cache_; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h b/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h index 73af730..ac03328e9 100644 --- a/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h +++ b/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h
@@ -82,8 +82,8 @@ return parent_changed; DCHECK(!IsParentAlias()) << "Changed the state of an alias node."; - SetChanged(); state_ = std::move(state); + SetChanged(); return true; }
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.cc b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.cc index ca1a308..374c7b4 100644 --- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.cc +++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.cc
@@ -20,6 +20,10 @@ g_clip_cache_generation++; } +bool GeometryMapperClipCache::IsValid() const { + return cache_generation_ == g_clip_cache_generation; +} + void GeometryMapperClipCache::InvalidateCacheIfNeeded() { if (cache_generation_ != g_clip_cache_generation) { clip_cache_.clear();
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.h b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.h index 35215be..b080c99 100644 --- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.h +++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.h
@@ -52,6 +52,7 @@ void SetCachedClip(const ClipAndTransform&, const FloatClipRect&); static void ClearCache(); + bool IsValid() const; private: struct ClipCacheEntry {
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc index cad4fc4..b5dd478 100644 --- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc +++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc
@@ -17,15 +17,8 @@ s_global_generation++; } -// Computes flatten(m) ^ -1, return true if the inversion succeeded. -static bool InverseProjection(const TransformationMatrix& m, - TransformationMatrix& out) { - out = m; - out.FlattenTo2d(); - if (!out.IsInvertible()) - return false; - out = out.Inverse(); - return true; +bool GeometryMapperTransformCache::IsValid() const { + return cache_generation_ == s_global_generation; } void GeometryMapperTransformCache::Update( @@ -120,8 +113,13 @@ if (node.FlattensInheritedTransform()) screen_transform_->to_screen.FlattenTo2d(); screen_transform_->to_screen.Multiply(local); - screen_transform_->projection_from_screen_is_valid = InverseProjection( - screen_transform_->to_screen, screen_transform_->projection_from_screen); + + auto to_screen_flattened = screen_transform_->to_screen; + to_screen_flattened.FlattenTo2d(); + screen_transform_->projection_from_screen_is_valid = + to_screen_flattened.IsInvertible(); + if (screen_transform_->projection_from_screen_is_valid) + screen_transform_->projection_from_screen = to_screen_flattened.Inverse(); } #if DCHECK_IS_ON()
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h index 94fd1f0..2ceeeb8e 100644 --- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h +++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h
@@ -22,6 +22,7 @@ GeometryMapperTransformCache() = default; static void ClearCache(); + bool IsValid() const; void UpdateIfNeeded(const TransformPaintPropertyNode& node) { if (cache_generation_ != s_global_generation)
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h b/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h index 5760dca..97aeb40 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h +++ b/third_party/blink/renderer/platform/graphics/paint/paint_property_node.h
@@ -122,8 +122,8 @@ if (parent == parent_) return false; - SetChanged(); parent_ = parent; + static_cast<NodeType*>(this)->SetChanged(); return true; }
diff --git a/third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h b/third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h index c0cecac..35f8337 100644 --- a/third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h +++ b/third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h
@@ -91,9 +91,9 @@ if (state == state_) return parent_changed; - SetChanged(); state_ = std::move(state); Validate(); + SetChanged(); return true; }
diff --git a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h index ee5ac86..cfaee4d 100644 --- a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h +++ b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/platform/geometry/float_point_3d.h" #include "third_party/blink/renderer/platform/graphics/compositing_reasons.h" #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h" +#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper_clip_cache.h" #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_property_node.h" #include "third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h" @@ -97,8 +98,8 @@ return parent_changed; DCHECK(!IsParentAlias()) << "Changed the state of an alias node."; - SetChanged(); state_ = std::move(state); + SetChanged(); CheckAndUpdateIsIdentityOr2DTranslation(); Validate(); return true; @@ -194,6 +195,8 @@ size_t CacheMemoryUsageInBytes() const; private: + friend class PaintPropertyNode<TransformPaintPropertyNode>; + TransformPaintPropertyNode(const TransformPaintPropertyNode* parent, State&& state, bool is_parent_alias) @@ -226,6 +229,18 @@ #endif } + void SetChanged() { + // TODO(crbug.com/814815): This is a workaround of the bug. When the bug is + // fixed, change the following condition to + // DCHECK(!transform_cache_ || !transform_cache_->IsValid()); + if (transform_cache_ && transform_cache_->IsValid()) { + DLOG(WARNING) << "Transform tree changed without invalidating the cache."; + GeometryMapperTransformCache::ClearCache(); + GeometryMapperClipCache::ClearCache(); + } + PaintPropertyNode::SetChanged(); + } + // For access to GetTransformCache() and SetCachedTransform. friend class GeometryMapper; friend class GeometryMapperTest; @@ -239,6 +254,7 @@ return *transform_cache_; } void UpdateScreenTransform() const { + DCHECK(transform_cache_); transform_cache_->UpdateScreenTransform(*this); }
diff --git a/third_party/blink/tools/blinkpy/common/path_finder.py b/third_party/blink/tools/blinkpy/common/path_finder.py index 5fc1f4a..4a25e41b 100644 --- a/third_party/blink/tools/blinkpy/common/path_finder.py +++ b/third_party/blink/tools/blinkpy/common/path_finder.py
@@ -95,6 +95,18 @@ sys.path.append(path) +def _does_blink_web_tests_exist(): + return os.path.exists(os.path.join(get_chromium_src_dir(), 'third_party', + 'blink', 'web_tests')) + + +TESTS_IN_BLINK = _does_blink_web_tests_exist() +# LayoutTests / web_tests path relative to the repository root. +# Path separators are always '/', and this contains the trailing '/'. +RELATIVE_WEB_TESTS = ('third_party/blink/web_tests/' if TESTS_IN_BLINK + else 'third_party/WebKit/LayoutTests/') +WEB_TESTS_LAST_COMPONENT = 'web_tests' if TESTS_IN_BLINK else 'LayoutTests' + class PathFinder(object): def __init__(self, filesystem, sys_path=None, env_path=None): @@ -107,7 +119,10 @@ def chromium_base(self): return self._filesystem.dirname(self._filesystem.dirname(self._blink_base())) + # TODO(tkent): Rename this to web_tests_dir(). def layout_tests_dir(self): + if TESTS_IN_BLINK: + return self.path_from_chromium_base('third_party', 'blink', 'web_tests') return self.path_from_chromium_base('third_party', 'WebKit', 'LayoutTests') def perf_tests_dir(self):
diff --git a/third_party/blink/tools/blinkpy/common/path_finder_unittest.py b/third_party/blink/tools/blinkpy/common/path_finder_unittest.py index a10545f..edc6ff0 100644 --- a/third_party/blink/tools/blinkpy/common/path_finder_unittest.py +++ b/third_party/blink/tools/blinkpy/common/path_finder_unittest.py
@@ -5,6 +5,8 @@ import unittest from blinkpy.common.path_finder import PathFinder +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS +from blinkpy.common.path_finder import TESTS_IN_BLINK from blinkpy.common.system.filesystem_mock import MockFileSystem @@ -24,7 +26,7 @@ finder = PathFinder(MockFileSystem()) self.assertEqual( finder.layout_tests_dir(), - '/mock-checkout/third_party/WebKit/LayoutTests') + '/mock-checkout/' + RELATIVE_WEB_TESTS[:-1]) def test_layout_tests_dir_with_backslash_sep(self): filesystem = MockFileSystem() @@ -32,9 +34,14 @@ filesystem.path_to_module = lambda _: ( 'C:\\mock-checkout\\third_party\\blink\\tools\\blinkpy\\foo.py') finder = PathFinder(filesystem) - self.assertEqual( - finder.layout_tests_dir(), - 'C:\\mock-checkout\\third_party\\WebKit\\LayoutTests') + if TESTS_IN_BLINK: + self.assertEqual( + finder.layout_tests_dir(), + 'C:\\mock-checkout\\third_party\\blink\\web_tests') + else: + self.assertEqual( + finder.layout_tests_dir(), + 'C:\\mock-checkout\\third_party\\WebKit\\LayoutTests') def test_perf_tests_dir(self): finder = PathFinder(MockFileSystem()) @@ -46,7 +53,7 @@ finder = PathFinder(MockFileSystem()) self.assertEqual( finder.path_from_layout_tests('external', 'wpt'), - '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt') + '/mock-checkout/' + RELATIVE_WEB_TESTS + 'external/wpt') def test_depot_tools_base_not_found(self): filesystem = MockFileSystem()
diff --git a/third_party/blink/tools/blinkpy/style/checker.py b/third_party/blink/tools/blinkpy/style/checker.py index 8ca7b68c..37dd7b9 100644 --- a/third_party/blink/tools/blinkpy/style/checker.py +++ b/third_party/blink/tools/blinkpy/style/checker.py
@@ -190,7 +190,9 @@ # This list should be in addition to files with FileType.NONE. Files # with FileType.NONE are automatically skipped without warning. _SKIPPED_FILES_WITHOUT_WARNING = [ + # TODO(tkent): Remove the item for LayoutTests. 'LayoutTests' + os.path.sep, + 'web_tests' + os.path.sep, 'third_party' + os.path.sep + 'blink' + os.path.sep + 'renderer' + os.path.sep + 'devtools' + os.path.sep + 'protocol.json', ]
diff --git a/third_party/blink/tools/blinkpy/tool/commands/queries.py b/third_party/blink/tools/blinkpy/tool/commands/queries.py index 1f1c888..dacafd20 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/queries.py +++ b/third_party/blink/tools/blinkpy/tool/commands/queries.py
@@ -33,6 +33,7 @@ from optparse import make_option +from blinkpy.common.path_finder import WEB_TESTS_LAST_COMPONENT from blinkpy.common.system.crash_logs import CrashLogs from blinkpy.tool.commands.command import Command from blinkpy.web_tests.models.test_expectations import TestExpectations @@ -107,7 +108,7 @@ layout_tests_dir = default_port.layout_tests_dir() for file in files: if file.startswith(layout_tests_dir): - file = file.replace(layout_tests_dir, 'LayoutTests') + file = file.replace(layout_tests_dir, WEB_TESTS_LAST_COMPONENT) print file return
diff --git a/third_party/blink/tools/blinkpy/tool/commands/queries_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/queries_unittest.py index 9d72145..8d19afd 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/queries_unittest.py +++ b/third_party/blink/tools/blinkpy/tool/commands/queries_unittest.py
@@ -30,6 +30,7 @@ import optparse import unittest +from blinkpy.common.path_finder import WEB_TESTS_LAST_COMPONENT from blinkpy.common.system.output_capture import OutputCapture from blinkpy.tool.commands.queries import PrintBaselines, PrintExpectations from blinkpy.tool.mock_tool import MockBlinkTool @@ -104,10 +105,10 @@ def test_paths(self): self.run_test([], - ('LayoutTests/TestExpectations\n' - 'LayoutTests/NeverFixTests\n' - 'LayoutTests/StaleTestExpectations\n' - 'LayoutTests/SlowTests\n'), + (WEB_TESTS_LAST_COMPONENT + '/TestExpectations\n' + + WEB_TESTS_LAST_COMPONENT + '/NeverFixTests\n' + + WEB_TESTS_LAST_COMPONENT + '/StaleTestExpectations\n' + + WEB_TESTS_LAST_COMPONENT + '/SlowTests\n'), paths=True)
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py index 00547b94..e3723570 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py +++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
@@ -32,6 +32,7 @@ import optparse import re +from blinkpy.common.path_finder import WEB_TESTS_LAST_COMPONENT from blinkpy.common.memoized import memoized from blinkpy.common.net.buildbot import Build from blinkpy.tool.commands.command import Command @@ -435,7 +436,7 @@ def unstaged_baselines(self): """Returns absolute paths for unstaged (including untracked) baselines.""" - baseline_re = re.compile(r'.*[\\/]LayoutTests[\\/].*-expected\.(txt|png|wav)$') + baseline_re = re.compile(r'.*[\\/]' + WEB_TESTS_LAST_COMPONENT + r'[\\/].*-expected\.(txt|png|wav)$') unstaged_changes = self._tool.git().unstaged_changes() return sorted(self._tool.git().absolute_path(path) for path in unstaged_changes if re.match(baseline_re, path))
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py index e3d0e23..79fd765 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py +++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
@@ -11,6 +11,7 @@ from blinkpy.common.net.git_cl import TryJobStatus from blinkpy.common.net.git_cl_mock import MockGitCL from blinkpy.common.net.layout_test_results import LayoutTestResults +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.log_testing import LoggingTestCase from blinkpy.tool.commands.rebaseline import TestBaselineSet from blinkpy.tool.commands.rebaseline_cl import RebaselineCL @@ -36,8 +37,8 @@ git = MockGit(filesystem=self.tool.filesystem, executive=self.tool.executive) git.changed_files = lambda **_: [ - 'third_party/WebKit/LayoutTests/one/text-fail.html', - 'third_party/WebKit/LayoutTests/one/flaky-fail.html', + RELATIVE_WEB_TESTS + 'one/text-fail.html', + RELATIVE_WEB_TESTS + 'one/flaky-fail.html', ] self.tool.git = lambda: git @@ -170,13 +171,13 @@ def test_execute_with_unstaged_baselines_aborts(self): git = self.tool.git() git.unstaged_changes = lambda: { - 'third_party/WebKit/LayoutTests/my-test-expected.txt': '?' + RELATIVE_WEB_TESTS + 'my-test-expected.txt': '?' } exit_code = self.command.execute(self.command_options(), [], self.tool) self.assertEqual(exit_code, 1) self.assertLog([ 'ERROR: Aborting: there are unstaged baselines:\n', - 'ERROR: /mock-checkout/third_party/WebKit/LayoutTests/' + 'ERROR: /mock-checkout/' + RELATIVE_WEB_TESTS + 'my-test-expected.txt\n', ])
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py index be4b1fc..7022cc80 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py +++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
@@ -8,6 +8,7 @@ from blinkpy.common.net.buildbot import Build from blinkpy.common.net.layout_test_results import LayoutTestResults +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.executive_mock import MockExecutive from blinkpy.tool.commands.rebaseline import ( AbstractParallelRebaselineCommand, Rebaseline, TestBaselineSet @@ -138,17 +139,17 @@ def test_unstaged_baselines(self): git = self.tool.git() git.unstaged_changes = lambda: { - 'third_party/WebKit/LayoutTests/x/foo-expected.txt': 'M', - 'third_party/WebKit/LayoutTests/x/foo-expected.something': '?', - 'third_party/WebKit/LayoutTests/x/foo-expected.png': '?', - 'third_party/WebKit/LayoutTests/x/foo.html': 'M', + RELATIVE_WEB_TESTS + 'x/foo-expected.txt': 'M', + RELATIVE_WEB_TESTS + 'x/foo-expected.something': '?', + RELATIVE_WEB_TESTS + 'x/foo-expected.png': '?', + RELATIVE_WEB_TESTS + 'x/foo.html': 'M', 'docs/something.md': '?', } self.assertEqual( self.command.unstaged_baselines(), [ - '/mock-checkout/third_party/WebKit/LayoutTests/x/foo-expected.png', - '/mock-checkout/third_party/WebKit/LayoutTests/x/foo-expected.txt', + '/mock-checkout/' + RELATIVE_WEB_TESTS + 'x/foo-expected.png', + '/mock-checkout/' + RELATIVE_WEB_TESTS + 'x/foo-expected.txt', ])
diff --git a/third_party/blink/tools/blinkpy/w3c/chromium_commit_unittest.py b/third_party/blink/tools/blinkpy/w3c/chromium_commit_unittest.py index 69bd79b8a..5a2a903 100644 --- a/third_party/blink/tools/blinkpy/w3c/chromium_commit_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/chromium_commit_unittest.py
@@ -5,11 +5,12 @@ import unittest from blinkpy.common.host_mock import MockHost +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.executive import ScriptError from blinkpy.common.system.executive_mock import MockExecutive, mock_git_commands from blinkpy.w3c.chromium_commit import ChromiumCommit -CHROMIUM_WPT_DIR = 'third_party/WebKit/LayoutTests/external/wpt/' +CHROMIUM_WPT_DIR = RELATIVE_WEB_TESTS + 'external/wpt/' class ChromiumCommitTest(unittest.TestCase):
diff --git a/third_party/blink/tools/blinkpy/w3c/chromium_exportable_commits_unittest.py b/third_party/blink/tools/blinkpy/w3c/chromium_exportable_commits_unittest.py index af84a4a0..1f85a807 100644 --- a/third_party/blink/tools/blinkpy/w3c/chromium_exportable_commits_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/chromium_exportable_commits_unittest.py
@@ -5,6 +5,7 @@ import unittest from blinkpy.common.host_mock import MockHost +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.executive_mock import mock_git_commands from blinkpy.w3c.chromium_commit import ChromiumCommit from blinkpy.w3c.chromium_commit_mock import MockChromiumCommit @@ -30,8 +31,8 @@ 'rev-parse': 'add087a97844f4b9e307d9a216940582d96db306', 'crrev-parse': 'add087a97844f4b9e307d9a216940582d96db306', 'diff': 'fake diff', - 'diff-tree': 'third_party/WebKit/LayoutTests/external/wpt/some\n' - 'third_party/WebKit/LayoutTests/external/wpt/files', + 'diff-tree': (RELATIVE_WEB_TESTS + 'external/wpt/some\n' + + RELATIVE_WEB_TESTS + 'external/wpt/files'), 'format-patch': 'hey I\'m a patch', 'footers': 'cr-rev-position', }, strict=True) @@ -43,19 +44,19 @@ self.assertEqual(host.executive.calls, [ ['git', 'rev-parse', '--show-toplevel'], ['git', 'rev-list', 'beefcafe..HEAD', '--reverse', '--', - 'add087a97844f4b9e307d9a216940582d96db306/third_party/WebKit/LayoutTests/external/wpt/'], + 'add087a97844f4b9e307d9a216940582d96db306/' + RELATIVE_WEB_TESTS + 'external/wpt/'], ['git', 'footers', '--position', 'add087a97844f4b9e307d9a216940582d96db306'], ['git', 'show', '--format=%B', '--no-patch', 'add087a97844f4b9e307d9a216940582d96db306'], ['git', 'diff-tree', '--name-only', '--no-commit-id', '-r', 'add087a97844f4b9e307d9a216940582d96db306', '--', - '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt'], + '/mock-checkout/' + RELATIVE_WEB_TESTS + 'external/wpt'], ['git', 'format-patch', '-1', '--stdout', 'add087a97844f4b9e307d9a216940582d96db306', '--', - 'third_party/WebKit/LayoutTests/external/wpt/some', 'third_party/WebKit/LayoutTests/external/wpt/files'], + RELATIVE_WEB_TESTS + 'external/wpt/some', RELATIVE_WEB_TESTS + 'external/wpt/files'], ]) def test_exportable_commits_since_require_clean_by_default(self): host = MockHost() host.executive = mock_git_commands({ - 'diff-tree': 'third_party/WebKit/LayoutTests/external/wpt/some_files', + 'diff-tree': RELATIVE_WEB_TESTS + 'external/wpt/some_files', 'footers': 'cr-rev-position', 'format-patch': 'hey I\'m a patch', 'rev-list': 'add087a97844f4b9e307d9a216940582d96db306\n' @@ -75,7 +76,7 @@ def test_exportable_commits_since_not_require_clean(self): host = MockHost() host.executive = mock_git_commands({ - 'diff-tree': 'third_party/WebKit/LayoutTests/external/wpt/some_files', + 'diff-tree': RELATIVE_WEB_TESTS + 'external/wpt/some_files', 'footers': 'cr-rev-position', 'format-patch': 'hey I\'m a patch', 'rev-list': 'add087a97844f4b9e307d9a216940582d96db306\n'
diff --git a/third_party/blink/tools/blinkpy/w3c/common.py b/third_party/blink/tools/blinkpy/w3c/common.py index a0f8932..518de39 100644 --- a/third_party/blink/tools/blinkpy/w3c/common.py +++ b/third_party/blink/tools/blinkpy/w3c/common.py
@@ -7,6 +7,8 @@ import json import logging +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS + WPT_GH_ORG = 'web-platform-tests' WPT_GH_REPO_NAME = 'wpt' @@ -23,7 +25,7 @@ DEFAULT_WPT_COMMITTER_EMAIL = 'blink-w3c-test-autoroller@chromium.org' # TODO(qyearsley): Avoid hard-coding third_party/WebKit/LayoutTests. -CHROMIUM_WPT_DIR = 'third_party/WebKit/LayoutTests/external/wpt/' +CHROMIUM_WPT_DIR = RELATIVE_WEB_TESTS + 'external/wpt/' _log = logging.getLogger(__name__)
diff --git a/third_party/blink/tools/blinkpy/w3c/directory_owners_extractor_unittest.py b/third_party/blink/tools/blinkpy/w3c/directory_owners_extractor_unittest.py index 553f030a..e176eb5 100644 --- a/third_party/blink/tools/blinkpy/w3c/directory_owners_extractor_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/directory_owners_extractor_unittest.py
@@ -4,19 +4,21 @@ import unittest +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.filesystem_mock import MockFileSystem from blinkpy.w3c.directory_owners_extractor import DirectoryOwnersExtractor -ABS_WPT_BASE = '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt' -REL_WPT_BASE = 'third_party/WebKit/LayoutTests/external/wpt' +MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS +ABS_WPT_BASE = MOCK_WEB_TESTS + 'external/wpt' +REL_WPT_BASE = RELATIVE_WEB_TESTS + 'external/wpt' class DirectoryOwnersExtractorTest(unittest.TestCase): def setUp(self): # We always have an OWNERS file at LayoutTests/external. self.filesystem = MockFileSystem(files={ - '/mock-checkout/third_party/WebKit/LayoutTests/external/OWNERS': 'ecosystem-infra@chromium.org' + MOCK_WEB_TESTS + 'external/OWNERS': 'ecosystem-infra@chromium.org' }) self.extractor = DirectoryOwnersExtractor(self.filesystem) @@ -103,7 +105,7 @@ ABS_WPT_BASE + '/x/y/z.html': '', }) self.assertEqual(self.extractor.find_owners_file(REL_WPT_BASE + '/x/y'), - '/mock-checkout/third_party/WebKit/LayoutTests/external/OWNERS') + MOCK_WEB_TESTS + 'external/OWNERS') def test_find_owners_file_takes_four_kinds_of_paths(self): owners_path = ABS_WPT_BASE + '/foo/OWNERS'
diff --git a/third_party/blink/tools/blinkpy/w3c/gerrit_unittest.py b/third_party/blink/tools/blinkpy/w3c/gerrit_unittest.py index a771d09..9aba2b72 100644 --- a/third_party/blink/tools/blinkpy/w3c/gerrit_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/gerrit_unittest.py
@@ -5,6 +5,7 @@ import unittest from blinkpy.common.host_mock import MockHost +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.executive_mock import mock_git_commands from blinkpy.w3c.gerrit import GerritCL from blinkpy.w3c.gerrit_mock import MockGerritAPI @@ -70,7 +71,7 @@ 'revisions': {'1': { 'commit_with_footers': 'fake subject', 'files': { - 'third_party/WebKit/LayoutTests/external/wpt/foo/bar.html': '', + RELATIVE_WEB_TESTS + 'external/wpt/foo/bar.html': '', } }}, 'owner': {'email': 'test@chromium.org'}, @@ -87,7 +88,7 @@ 'revisions': {'1': { 'commit_with_footers': 'fake subject', 'files': { - 'third_party/WebKit/LayoutTests/foo/bar.html': '', + RELATIVE_WEB_TESTS + 'foo/bar.html': '', } }}, 'owner': {'email': 'test@chromium.org'}, @@ -104,7 +105,7 @@ 'revisions': {'1': { 'commit_with_footers': 'fake subject\nNo-Export: true', 'files': { - 'third_party/WebKit/LayoutTests/external/wpt/foo/bar.html': '', + RELATIVE_WEB_TESTS + 'external/wpt/foo/bar.html': '', } }}, 'owner': {'email': 'test@chromium.org'}, @@ -121,7 +122,7 @@ 'revisions': {'1': { 'commit_with_footers': 'fake subject\nNOEXPORT=true', 'files': { - 'third_party/WebKit/LayoutTests/external/wpt/foo/bar.html': '', + RELATIVE_WEB_TESTS + 'external/wpt/foo/bar.html': '', } }}, 'owner': {'email': 'test@chromium.org'}, @@ -138,7 +139,7 @@ 'revisions': {'1': { 'commit_with_footers': 'fake subject', 'files': { - 'third_party/WebKit/LayoutTests/external/wpt/foo/bar.html': '', + RELATIVE_WEB_TESTS + 'external/wpt/foo/bar.html': '', } }}, 'owner': {'email': 'test@chromium.org'},
diff --git a/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py b/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py index dd5e3f3..99eb8a1c 100644 --- a/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py
@@ -7,6 +7,7 @@ from blinkpy.common.checkout.git_mock import MockGit from blinkpy.common.host_mock import MockHost +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.executive_mock import mock_git_commands from blinkpy.common.system.filesystem_mock import MockFileSystem from blinkpy.w3c.local_wpt_mock import MockLocalWPT @@ -14,13 +15,15 @@ from blinkpy.w3c.wpt_expectations_updater import UMBRELLA_BUG +MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS + class ImportNotifierTest(unittest.TestCase): def setUp(self): self.host = MockHost() # Mock a virtual test suite at virtual/gpu/external/wpt/foo. self.host.filesystem = MockFileSystem({ - '/mock-checkout/third_party/WebKit/LayoutTests/VirtualTestSuites': + MOCK_WEB_TESTS + 'VirtualTestSuites': '[{"prefix": "gpu", "base": "external/wpt/foo", "args": ["--foo"]}]' }) self.git = self.host.git() @@ -29,16 +32,16 @@ def test_find_changed_baselines_of_tests(self): changed_files = [ - 'third_party/WebKit/LayoutTests/external/wpt/foo/bar.html', - 'third_party/WebKit/LayoutTests/external/wpt/foo/bar-expected.txt', - 'third_party/WebKit/LayoutTests/platform/linux/external/wpt/foo/bar-expected.txt', - 'third_party/WebKit/LayoutTests/external/wpt/random_stuff.html', + RELATIVE_WEB_TESTS + 'external/wpt/foo/bar.html', + RELATIVE_WEB_TESTS + 'external/wpt/foo/bar-expected.txt', + RELATIVE_WEB_TESTS + 'platform/linux/external/wpt/foo/bar-expected.txt', + RELATIVE_WEB_TESTS + 'external/wpt/random_stuff.html', ] self.git.changed_files = lambda: changed_files self.assertEqual(self.notifier.find_changed_baselines_of_tests(['external/wpt/foo/bar.html']), {'external/wpt/foo/bar.html': [ - 'third_party/WebKit/LayoutTests/external/wpt/foo/bar-expected.txt', - 'third_party/WebKit/LayoutTests/platform/linux/external/wpt/foo/bar-expected.txt', + RELATIVE_WEB_TESTS + 'external/wpt/foo/bar-expected.txt', + RELATIVE_WEB_TESTS + 'platform/linux/external/wpt/foo/bar-expected.txt', ]}) self.assertEqual(self.notifier.find_changed_baselines_of_tests(set()), {}) @@ -83,12 +86,12 @@ def test_examine_baseline_changes(self): self.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo/OWNERS', + MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'test@chromium.org' ) changed_test_baselines = {'external/wpt/foo/bar.html': [ - 'third_party/WebKit/LayoutTests/external/wpt/foo/bar-expected.txt', - 'third_party/WebKit/LayoutTests/platform/linux/external/wpt/foo/bar-expected.txt', + RELATIVE_WEB_TESTS + 'external/wpt/foo/bar-expected.txt', + RELATIVE_WEB_TESTS + 'platform/linux/external/wpt/foo/bar-expected.txt', ]} gerrit_url_with_ps = 'https://crrev.com/c/12345/3/' self.notifier.more_failures_in_baseline = lambda _: True @@ -98,17 +101,17 @@ self.notifier.new_failures_by_directory, {'external/wpt/foo': [ TestFailure(TestFailure.BASELINE_CHANGE, 'external/wpt/foo/bar.html', - baseline_path='third_party/WebKit/LayoutTests/external/wpt/foo/bar-expected.txt', + baseline_path=RELATIVE_WEB_TESTS + 'external/wpt/foo/bar-expected.txt', gerrit_url_with_ps=gerrit_url_with_ps), TestFailure(TestFailure.BASELINE_CHANGE, 'external/wpt/foo/bar.html', - baseline_path='third_party/WebKit/LayoutTests/platform/linux/external/wpt/foo/bar-expected.txt', + baseline_path=RELATIVE_WEB_TESTS + 'platform/linux/external/wpt/foo/bar-expected.txt', gerrit_url_with_ps=gerrit_url_with_ps), ]} ) def test_examine_new_test_expectations(self): self.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo/OWNERS', + MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'test@chromium.org' ) test_expectations = {'external/wpt/foo/bar.html': [ @@ -142,14 +145,14 @@ self.local_wpt.is_commit_affecting_directory = _is_commit_affecting_directory self.assertEqual( - self.notifier.format_commit_list(imported_commits, '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo'), + self.notifier.format_commit_list(imported_commits, MOCK_WEB_TESTS + 'external/wpt/foo'), u'Subject 1: https://github.com/web-platform-tests/wpt/commit/SHA1 [affecting this directory]\n' u'ABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ: https://github.com/web-platform-tests/wpt/commit/SHA2\n' ) def test_find_owned_directory_non_virtual(self): self.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo/OWNERS', + MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'test@chromium.org' ) self.assertEqual(self.notifier.find_owned_directory('external/wpt/foo/bar.html'), 'external/wpt/foo') @@ -157,20 +160,20 @@ def test_find_owned_directory_virtual(self): self.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo/OWNERS', + MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'test@chromium.org' ) self.assertEqual(self.notifier.find_owned_directory('virtual/gpu/external/wpt/foo/bar.html'), 'external/wpt/foo') def test_create_bugs_from_new_failures(self): self.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo/OWNERS', + MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', '# COMPONENT: Blink>Infra>Ecosystem\n' '# WPT-NOTIFY: true\n' 'foolip@chromium.org\n' ) self.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/bar/OWNERS', + MOCK_WEB_TESTS + 'external/wpt/bar/OWNERS', 'test@chromium.org' ) self.notifier.new_failures_by_directory = { @@ -202,19 +205,19 @@ def test_test_failure_to_str_baseline_change(self): failure = TestFailure( TestFailure.BASELINE_CHANGE, 'external/wpt/foo/bar.html', - baseline_path='third_party/WebKit/LayoutTests/external/wpt/foo/bar-expected.txt', + baseline_path=RELATIVE_WEB_TESTS + 'external/wpt/foo/bar-expected.txt', gerrit_url_with_ps='https://crrev.com/c/12345/3/') self.assertEqual(str(failure), - 'external/wpt/foo/bar.html new failing tests: https://crrev.com/c/12345/3/' - 'third_party/WebKit/LayoutTests/external/wpt/foo/bar-expected.txt') + 'external/wpt/foo/bar.html new failing tests: https://crrev.com/c/12345/3/' + + RELATIVE_WEB_TESTS + 'external/wpt/foo/bar-expected.txt') platform_failure = TestFailure( TestFailure.BASELINE_CHANGE, 'external/wpt/foo/bar.html', - baseline_path='third_party/WebKit/LayoutTests/platform/linux/external/wpt/foo/bar-expected.txt', + baseline_path=RELATIVE_WEB_TESTS + 'platform/linux/external/wpt/foo/bar-expected.txt', gerrit_url_with_ps='https://crrev.com/c/12345/3/') self.assertEqual(str(platform_failure), - '[ Linux ] external/wpt/foo/bar.html new failing tests: https://crrev.com/c/12345/3/' - 'third_party/WebKit/LayoutTests/platform/linux/external/wpt/foo/bar-expected.txt') + '[ Linux ] external/wpt/foo/bar.html new failing tests: https://crrev.com/c/12345/3/' + + RELATIVE_WEB_TESTS + 'platform/linux/external/wpt/foo/bar-expected.txt') def test_test_failure_to_str_new_expectation(self): failure = TestFailure(
diff --git a/third_party/blink/tools/blinkpy/w3c/test_copier_unittest.py b/third_party/blink/tools/blinkpy/w3c/test_copier_unittest.py index 2ebbb547..744b0007 100644 --- a/third_party/blink/tools/blinkpy/w3c/test_copier_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/test_copier_unittest.py
@@ -26,22 +26,25 @@ # SUCH DAMAGE. from blinkpy.common.host_mock import MockHost +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.executive_mock import MockExecutive, ScriptError from blinkpy.common.system.filesystem_mock import MockFileSystem from blinkpy.common.system.log_testing import LoggingTestCase from blinkpy.w3c.test_copier import TestCopier +MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS + FAKE_SOURCE_REPO_DIR = '/blink' FAKE_FILES = { - '/mock-checkout/third_party/Webkit/LayoutTests/external/OWNERS': '', + MOCK_WEB_TESTS + 'external/OWNERS': '', '/blink/w3c/dir/has_shebang.txt': '#!', '/blink/w3c/dir/README.txt': '', '/blink/w3c/dir/OWNERS': '', '/blink/w3c/dir/reftest.list': '', - '/mock-checkout/third_party/WebKit/LayoutTests/external/README.txt': '', - '/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations': '', + MOCK_WEB_TESTS + 'external/README.txt': '', + MOCK_WEB_TESTS + 'W3CImportExpectations': '', } @@ -95,14 +98,14 @@ copier.do_import() self.assertEqual( host.filesystem.executable_files, - set(['/mock-checkout/third_party/WebKit/LayoutTests/external/blink/w3c/dir/has_shebang.txt'])) + set([MOCK_WEB_TESTS + 'external/blink/w3c/dir/has_shebang.txt'])) def test_ref_test_with_ref_is_copied(self): host = MockHost() host.filesystem = MockFileSystem(files={ '/blink/w3c/dir1/my-ref-test.html': '<html><head><link rel="match" href="ref-file.html" />test</head></html>', '/blink/w3c/dir1/ref-file.html': '<html><head>test</head></html>', - '/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations': '', + MOCK_WEB_TESTS + 'W3CImportExpectations': '', }) copier = TestCopier(host, FAKE_SOURCE_REPO_DIR) copier.find_importable_tests()
diff --git a/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py b/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py index aa0c9ce..0347a88 100644 --- a/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py
@@ -12,6 +12,7 @@ from blinkpy.common.net.git_cl import TryJobStatus from blinkpy.common.net.git_cl_mock import MockGitCL from blinkpy.common.net.network_transaction import NetworkTimeout +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.executive_mock import MockCall from blinkpy.common.system.executive_mock import MockExecutive from blinkpy.common.system.log_testing import LoggingTestCase @@ -24,12 +25,13 @@ from blinkpy.web_tests.builder_list import BuilderList +MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS + class TestImporterTest(LoggingTestCase): def test_update_expectations_for_cl_no_results(self): host = MockHost() - host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations', '') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'W3CImportExpectations', '') importer = TestImporter(host) importer.git_cl = MockGitCL(host, time_out=True) success = importer.update_expectations_for_cl() @@ -42,8 +44,7 @@ def test_update_expectations_for_cl_closed_cl(self): host = MockHost() - host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations', '') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'W3CImportExpectations', '') importer = TestImporter(host) importer.git_cl = MockGitCL(host, status='closed', try_job_results={ Build('builder-a', 123): TryJobStatus('COMPLETED', 'SUCCESS'), @@ -57,8 +58,7 @@ def test_update_expectations_for_cl_all_jobs_pass(self): host = MockHost() - host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations', '') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'W3CImportExpectations', '') importer = TestImporter(host) importer.git_cl = MockGitCL(host, status='lgtm', try_job_results={ Build('builder-a', 123): TryJobStatus('COMPLETED', 'SUCCESS'), @@ -72,8 +72,7 @@ def test_update_expectations_for_cl_fail_but_no_changes(self): host = MockHost() - host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations', '') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'W3CImportExpectations', '') importer = TestImporter(host) importer.git_cl = MockGitCL(host, status='lgtm', try_job_results={ Build('builder-a', 123): TryJobStatus('COMPLETED', 'FAILURE'), @@ -88,8 +87,7 @@ def test_run_commit_queue_for_cl_pass(self): host = MockHost() - host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations', '') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'W3CImportExpectations', '') importer = TestImporter(host) # Only the latest job for each builder is counted. importer.git_cl = MockGitCL(host, status='lgtm', try_job_results={ @@ -112,8 +110,7 @@ def test_run_commit_queue_for_cl_fail_cq(self): host = MockHost() - host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations', '') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'W3CImportExpectations', '') importer = TestImporter(host) importer.git_cl = MockGitCL(host, status='lgtm', try_job_results={ Build('cq-builder-a', 120): TryJobStatus('COMPLETED', 'SUCCESS'), @@ -135,8 +132,7 @@ def test_run_commit_queue_for_cl_fail_to_land(self): host = MockHost() - host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations', '') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'W3CImportExpectations', '') importer = TestImporter(host) # Only the latest job for each builder is counted. importer.git_cl = MockGitCL(host, status='lgtm', try_job_results={ @@ -161,8 +157,7 @@ def test_run_commit_queue_for_cl_closed_cl(self): host = MockHost() - host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations', '') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'W3CImportExpectations', '') importer = TestImporter(host) importer.git_cl = MockGitCL(host, status='closed', try_job_results={ Build('cq-builder-a', 120): TryJobStatus('COMPLETED', 'SUCCESS'), @@ -202,8 +197,8 @@ host, subject='My fake commit', patch=( 'Fake patch contents...\n' - '--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/outline-004.html\n' - '+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/outline-004.html\n' + '--- a/' + RELATIVE_WEB_TESTS + 'external/wpt/css/css-ui-3/outline-004.html\n' + '+++ b/' + RELATIVE_WEB_TESTS + 'external/wpt/css/css-ui-3/outline-004.html\n' '@@ -20,7 +20,7 @@\n' '...')) importer.exportable_but_not_exported_commits = lambda _: [fake_commit] @@ -243,13 +238,13 @@ def test_update_all_test_expectations_files(self): host = MockHost() - host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations'] = ( + host.filesystem.files[MOCK_WEB_TESTS + 'TestExpectations'] = ( 'Bug(test) some/test/a.html [ Failure ]\n' 'Bug(test) some/test/b.html [ Failure ]\n' 'Bug(test) some/test/c.html [ Failure ]\n') - host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/VirtualTestSuites'] = '[]' - host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/new/a.html'] = '' - host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/new/b.html'] = '' + host.filesystem.files[MOCK_WEB_TESTS + 'VirtualTestSuites'] = '[]' + host.filesystem.files[MOCK_WEB_TESTS + 'new/a.html'] = '' + host.filesystem.files[MOCK_WEB_TESTS + 'new/b.html'] = '' importer = TestImporter(host) deleted_tests = ['some/test/b.html'] renamed_test_pairs = { @@ -258,23 +253,23 @@ } importer.update_all_test_expectations_files(deleted_tests, renamed_test_pairs) self.assertMultiLineEqual( - host.filesystem.read_text_file('/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations'), + host.filesystem.read_text_file(MOCK_WEB_TESTS + 'TestExpectations'), ('Bug(test) new/a.html [ Failure ]\n' 'Bug(test) new/c.html [ Failure ]\n')) def test_get_directory_owners(self): host = MockHost() - host.filesystem.write_text_file('/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations', '') - host.filesystem.write_text_file('/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo/OWNERS', + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'W3CImportExpectations', '') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'someone@chromium.org\n') importer = TestImporter(host) - importer.chromium_git.changed_files = lambda: ['third_party/WebKit/LayoutTests/external/wpt/foo/x.html'] + importer.chromium_git.changed_files = lambda: [RELATIVE_WEB_TESTS + 'external/wpt/foo/x.html'] self.assertEqual(importer.get_directory_owners(), {('someone@chromium.org',): ['external/wpt/foo']}) def test_get_directory_owners_no_changed_files(self): host = MockHost() - host.filesystem.write_text_file('/mock-checkout/third_party/WebKit/LayoutTests/W3CImportExpectations', '') - host.filesystem.write_text_file('/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/foo/OWNERS', + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'W3CImportExpectations', '') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'someone@chromium.org\n') importer = TestImporter(host) self.assertEqual(importer.get_directory_owners(), {}) @@ -455,8 +450,7 @@ # asserts that TestImporter._generate_manifest would invoke the script. host = MockHost() importer = TestImporter(host) - blink_path = '/mock-checkout/third_party/WebKit' - host.filesystem.write_text_file(blink_path + '/LayoutTests/external/wpt/MANIFEST.json', '{}') + host.filesystem.write_text_file(MOCK_WEB_TESTS + 'external/wpt/MANIFEST.json', '{}') importer._generate_manifest() self.assertEqual( host.executive.calls, @@ -467,22 +461,22 @@ 'manifest', '--work', '--tests-root', - blink_path + '/LayoutTests/external/wpt', + MOCK_WEB_TESTS + 'external/wpt', ] ]) self.assertEqual(importer.chromium_git.added_paths, - {blink_path + '/LayoutTests/external/' + BASE_MANIFEST_NAME}) + {MOCK_WEB_TESTS + 'external/' + BASE_MANIFEST_NAME}) def test_only_wpt_manifest_changed(self): host = MockHost() importer = TestImporter(host) importer.chromium_git.changed_files = lambda: [ - 'third_party/WebKit/LayoutTests/external/' + BASE_MANIFEST_NAME, - 'third_party/WebKit/LayoutTests/external/wpt/foo/x.html'] + RELATIVE_WEB_TESTS + 'external/' + BASE_MANIFEST_NAME, + RELATIVE_WEB_TESTS + 'external/wpt/foo/x.html'] self.assertFalse(importer._only_wpt_manifest_changed()) importer.chromium_git.changed_files = lambda: [ - 'third_party/WebKit/LayoutTests/external/' + BASE_MANIFEST_NAME] + RELATIVE_WEB_TESTS + 'external/' + BASE_MANIFEST_NAME] self.assertTrue(importer._only_wpt_manifest_changed()) def test_delete_orphaned_baselines_basic(self):
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py index 927f449e..ae3155b 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py
@@ -5,23 +5,25 @@ import unittest from blinkpy.common.host_mock import MockHost +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.executive import ScriptError from blinkpy.common.system.executive_mock import MockExecutive from blinkpy.w3c.wpt_manifest import WPTManifest +MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS + class WPTManifestUnitTest(unittest.TestCase): def test_ensure_manifest_copies_new_manifest(self): host = MockHost() - manifest_path = '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json' + manifest_path = MOCK_WEB_TESTS + 'external/wpt/MANIFEST.json' self.assertFalse(host.filesystem.exists(manifest_path)) WPTManifest.ensure_manifest(host) self.assertTrue(host.filesystem.exists(manifest_path)) self.assertEqual(host.filesystem.written_files, {manifest_path: '{"manifest": "base"}'}) - webkit_base = '/mock-checkout/third_party/WebKit' self.assertEqual( host.executive.calls, [ @@ -31,14 +33,14 @@ 'manifest', '--work', '--tests-root', - webkit_base + '/LayoutTests/external/wpt', + MOCK_WEB_TESTS + 'external/wpt', ] ] ) def test_ensure_manifest_updates_manifest_if_it_exists(self): host = MockHost() - manifest_path = '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json' + manifest_path = MOCK_WEB_TESTS + 'external/wpt/MANIFEST.json' host.filesystem.write_text_file(manifest_path, '{"manifest": "NOT base"}') @@ -47,7 +49,6 @@ self.assertTrue(host.filesystem.exists(manifest_path)) self.assertEqual(host.filesystem.written_files, {manifest_path: '{"manifest": "base"}'}) - webkit_base = '/mock-checkout/third_party/WebKit' self.assertEqual( host.executive.calls, [ @@ -57,7 +58,7 @@ 'manifest', '--work', '--tests-root', - webkit_base + '/LayoutTests/external/wpt', + MOCK_WEB_TESTS + 'external/wpt', ] ] )
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder.py b/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder.py index df0a9bba..8f59516 100644 --- a/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder.py +++ b/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder.py
@@ -32,6 +32,7 @@ import math import re +from blinkpy.common.path_finder import TESTS_IN_BLINK from blinkpy.web_tests.layout_package.json_results_generator import convert_times_trie_to_flat_paths from blinkpy.web_tests.models import test_expectations @@ -45,7 +46,10 @@ self._port = port self._options = options self._filesystem = self._port.host.filesystem - self.LAYOUT_TESTS_DIRECTORIES = ('src', 'third_party', 'WebKit', 'LayoutTests') + if TESTS_IN_BLINK: + self.LAYOUT_TESTS_DIRECTORIES = ('src', 'third_party', 'blink', 'web_tests') + else: + self.LAYOUT_TESTS_DIRECTORIES = ('src', 'third_party', 'WebKit', 'LayoutTests') def find_tests(self, args, test_list=None, fastest_percentile=None): paths = self._strip_test_dir_prefixes(args)
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/android.py b/third_party/blink/tools/blinkpy/web_tests/port/android.py index a96179ff..574033e 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/android.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/android.py
@@ -36,6 +36,7 @@ import time from blinkpy.common import exit_codes +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.path_finder import get_chromium_src_dir from blinkpy.common.system.executive import ScriptError from blinkpy.common.system.profiler import SingleFileOutputProfiler @@ -103,8 +104,7 @@ # 1. as a virtual path in file urls that will be bridged to HTTP. # 2. pointing to some files that are pushed to the device for tests that # don't work on file-over-http (e.g. blob protocol tests). -DEVICE_WEBKIT_BASE_DIR = DEVICE_SOURCE_ROOT_DIR + 'third_party/WebKit/' -DEVICE_LAYOUT_TESTS_DIR = DEVICE_WEBKIT_BASE_DIR + 'LayoutTests/' +DEVICE_LAYOUT_TESTS_DIR = DEVICE_SOURCE_ROOT_DIR + RELATIVE_WEB_TESTS KPTR_RESTRICT_PATH = '/proc/sys/kernel/kptr_restrict'
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py index 3b4847c..94ae83b1 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/base.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -47,6 +47,7 @@ from blinkpy.common import read_checksum_from_png from blinkpy.common.memoized import memoized from blinkpy.common.path_finder import PathFinder +from blinkpy.common.path_finder import TESTS_IN_BLINK from blinkpy.common.system.executive import ScriptError from blinkpy.common.system.path import abspath_to_uri from blinkpy.w3c.wpt_manifest import WPTManifest @@ -254,6 +255,8 @@ '--ignore-certificate-errors-spki-list=' + WPT_FINGERPRINT + ',' + SXG_FINGERPRINT, '--user-data-dir'] + if TESTS_IN_BLINK: + flags += ['--tests-in-blink'] return flags def supports_per_test_timeout(self): @@ -1591,7 +1594,7 @@ def virtual_test_suites(self): if self._virtual_test_suites is None: path_to_virtual_test_suites = self._filesystem.join(self.layout_tests_dir(), 'VirtualTestSuites') - assert self._filesystem.exists(path_to_virtual_test_suites), 'LayoutTests/VirtualTestSuites not found' + assert self._filesystem.exists(path_to_virtual_test_suites), path_to_virtual_test_suites + ' not found' try: test_suite_json = json.loads(self._filesystem.read_text_file(path_to_virtual_test_suites)) self._virtual_test_suites = []
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py index 7aabee8..a77d830 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
@@ -32,6 +32,7 @@ import unittest from blinkpy.common.path_finder import PathFinder +from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.executive import ScriptError from blinkpy.common.system.executive_mock import MockExecutive from blinkpy.common.system.log_testing import LoggingTestCase @@ -44,6 +45,8 @@ from blinkpy.web_tests.port.test import add_unit_tests_to_mock_filesystem, LAYOUT_TEST_DIR, TestPort +MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS + class PortTest(LoggingTestCase): def make_port(self, executive=None, with_tests=False, port_name=None, **kwargs): @@ -110,95 +113,95 @@ port = self.make_port(port_name='foo') port.FALLBACK_PATHS = {'': ['foo']} test_file = 'fast/test.html' - port.host.filesystem.write_text_file('/mock-checkout/third_party/WebKit/LayoutTests/VirtualTestSuites', '[]') + port.host.filesystem.write_text_file(MOCK_WEB_TESTS + 'VirtualTestSuites', '[]') # The default baseline self.assertEqual(port.expected_baselines(test_file, '.txt'), [(None, 'fast/test-expected.txt')]) self.assertEqual(port.expected_filename(test_file, '.txt', return_default=False), None) self.assertEqual(port.expected_filename(test_file, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/fast/test-expected.txt') + MOCK_WEB_TESTS + 'fast/test-expected.txt') # Mismatch baseline self.assertEqual(port.expected_baselines(test_file, '.txt', match=False), [(None, 'fast/test-expected-mismatch.txt')]) self.assertEqual(port.expected_filename(test_file, '.txt', match=False), - '/mock-checkout/third_party/WebKit/LayoutTests/fast/test-expected-mismatch.txt') + MOCK_WEB_TESTS + 'fast/test-expected-mismatch.txt') # Platform-specific baseline self.assertEqual(port.baseline_version_dir(), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo') + MOCK_WEB_TESTS + 'platform/foo') port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/fast/test-expected.txt', 'foo') + MOCK_WEB_TESTS + 'platform/foo/fast/test-expected.txt', 'foo') self.assertEqual(port.expected_baselines(test_file, '.txt'), - [('/mock-checkout/third_party/WebKit/LayoutTests/platform/foo', 'fast/test-expected.txt')]) + [(MOCK_WEB_TESTS + 'platform/foo', 'fast/test-expected.txt')]) self.assertEqual(port.expected_filename(test_file, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/fast/test-expected.txt') + MOCK_WEB_TESTS + 'platform/foo/fast/test-expected.txt') self.assertEqual(port.expected_filename(test_file, '.txt', return_default=False), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/fast/test-expected.txt') + MOCK_WEB_TESTS + 'platform/foo/fast/test-expected.txt') def test_expected_baselines_flag_specific(self): port = self.make_port(port_name='foo') port.FALLBACK_PATHS = {'': ['foo']} test_file = 'fast/test.html' - port.host.filesystem.write_text_file('/mock-checkout/third_party/WebKit/LayoutTests/VirtualTestSuites', '[]') + port.host.filesystem.write_text_file(MOCK_WEB_TESTS + 'VirtualTestSuites', '[]') # pylint: disable=protected-access port._options.additional_platform_directory = [] port._options.additional_driver_flag = ['--special-flag'] self.assertEqual(port.baseline_search_path(), [ - '/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag/platform/foo', - '/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag', - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo']) + MOCK_WEB_TESTS + 'flag-specific/special-flag/platform/foo', + MOCK_WEB_TESTS + 'flag-specific/special-flag', + MOCK_WEB_TESTS + 'platform/foo']) self.assertEqual(port.baseline_version_dir(), - '/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag/platform/foo') + MOCK_WEB_TESTS + 'flag-specific/special-flag/platform/foo') # The default baseline self.assertEqual(port.expected_baselines(test_file, '.txt'), [(None, 'fast/test-expected.txt')]) self.assertEqual(port.expected_filename(test_file, '.txt', return_default=False), None) self.assertEqual(port.expected_filename(test_file, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/fast/test-expected.txt') + MOCK_WEB_TESTS + 'fast/test-expected.txt') # Platform-specific baseline port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/fast/test-expected.txt', 'foo') + MOCK_WEB_TESTS + 'platform/foo/fast/test-expected.txt', 'foo') self.assertEqual(port.expected_baselines(test_file, '.txt'), - [('/mock-checkout/third_party/WebKit/LayoutTests/platform/foo', 'fast/test-expected.txt')]) + [(MOCK_WEB_TESTS + 'platform/foo', 'fast/test-expected.txt')]) self.assertEqual(port.expected_filename(test_file, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/fast/test-expected.txt') + MOCK_WEB_TESTS + 'platform/foo/fast/test-expected.txt') self.assertEqual(port.expected_filename(test_file, '.txt', return_default=False), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/fast/test-expected.txt') + MOCK_WEB_TESTS + 'platform/foo/fast/test-expected.txt') # Flag-specific baseline port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag/fast/test-expected.txt', 'foo') + MOCK_WEB_TESTS + 'flag-specific/special-flag/fast/test-expected.txt', 'foo') self.assertEqual(port.expected_baselines(test_file, '.txt'), - [('/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag', 'fast/test-expected.txt')]) + [(MOCK_WEB_TESTS + 'flag-specific/special-flag', 'fast/test-expected.txt')]) self.assertEqual(port.expected_filename(test_file, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'flag-specific/special-flag/fast/test-expected.txt') self.assertEqual(port.expected_filename(test_file, '.txt', return_default=False), - '/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'flag-specific/special-flag/fast/test-expected.txt') # Flag-specific platform-specific baseline port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag/platform/foo/fast/test-expected.txt', 'foo') + MOCK_WEB_TESTS + 'flag-specific/special-flag/platform/foo/fast/test-expected.txt', 'foo') self.assertEqual( port.expected_baselines(test_file, '.txt'), - [('/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag/platform/foo', 'fast/test-expected.txt')]) + [(MOCK_WEB_TESTS + 'flag-specific/special-flag/platform/foo', 'fast/test-expected.txt')]) self.assertEqual( port.expected_filename(test_file, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag/platform/foo/fast/test-expected.txt') + MOCK_WEB_TESTS + 'flag-specific/special-flag/platform/foo/fast/test-expected.txt') self.assertEqual( port.expected_filename(test_file, '.txt', return_default=False), - '/mock-checkout/third_party/WebKit/LayoutTests/flag-specific/special-flag/platform/foo/fast/test-expected.txt') + MOCK_WEB_TESTS + 'flag-specific/special-flag/platform/foo/fast/test-expected.txt') def test_expected_baselines_virtual(self): port = self.make_port(port_name='foo') port.FALLBACK_PATHS = {'': ['foo']} virtual_test = 'virtual/flag/fast/test.html' port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/VirtualTestSuites', + MOCK_WEB_TESTS + 'VirtualTestSuites', '[{ "prefix": "flag", "base": "fast", "args": ["--flag"]}]') # The default baseline for base test @@ -206,56 +209,56 @@ [(None, 'virtual/flag/fast/test-expected.txt')]) self.assertEqual(port.expected_filename(virtual_test, '.txt', return_default=False), None) self.assertEqual(port.expected_filename(virtual_test, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/fast/test-expected.txt') + MOCK_WEB_TESTS + 'fast/test-expected.txt') self.assertEqual(port.expected_filename(virtual_test, '.txt', return_default=False, fallback_base_for_virtual=False), None) self.assertEqual(port.expected_filename(virtual_test, '.txt', fallback_base_for_virtual=False), - '/mock-checkout/third_party/WebKit/LayoutTests/virtual/flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'virtual/flag/fast/test-expected.txt') # Platform-specific baseline for base test port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/fast/test-expected.txt', 'foo') + MOCK_WEB_TESTS + 'platform/foo/fast/test-expected.txt', 'foo') self.assertEqual(port.expected_baselines(virtual_test, '.txt'), [(None, 'virtual/flag/fast/test-expected.txt')]) self.assertEqual(port.expected_filename(virtual_test, '.txt', return_default=False), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/fast/test-expected.txt') + MOCK_WEB_TESTS + 'platform/foo/fast/test-expected.txt') self.assertEqual(port.expected_filename(virtual_test, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/fast/test-expected.txt') + MOCK_WEB_TESTS + 'platform/foo/fast/test-expected.txt') self.assertEqual(port.expected_filename(virtual_test, '.txt', return_default=False, fallback_base_for_virtual=False), None) self.assertEqual(port.expected_filename(virtual_test, '.txt', fallback_base_for_virtual=False), - '/mock-checkout/third_party/WebKit/LayoutTests/virtual/flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'virtual/flag/fast/test-expected.txt') # The default baseline for virtual test port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/virtual/flag/fast/test-expected.txt', 'foo') + MOCK_WEB_TESTS + 'virtual/flag/fast/test-expected.txt', 'foo') self.assertEqual(port.expected_baselines(virtual_test, '.txt'), - [('/mock-checkout/third_party/WebKit/LayoutTests', 'virtual/flag/fast/test-expected.txt')]) + [(MOCK_WEB_TESTS[:-1], 'virtual/flag/fast/test-expected.txt')]) self.assertEqual(port.expected_filename(virtual_test, '.txt', return_default=False), - '/mock-checkout/third_party/WebKit/LayoutTests/virtual/flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'virtual/flag/fast/test-expected.txt') self.assertEqual(port.expected_filename(virtual_test, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/virtual/flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'virtual/flag/fast/test-expected.txt') self.assertEqual(port.expected_filename(virtual_test, '.txt', return_default=False, fallback_base_for_virtual=False), - '/mock-checkout/third_party/WebKit/LayoutTests/virtual/flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'virtual/flag/fast/test-expected.txt') self.assertEqual(port.expected_filename(virtual_test, '.txt', fallback_base_for_virtual=False), - '/mock-checkout/third_party/WebKit/LayoutTests/virtual/flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'virtual/flag/fast/test-expected.txt') # Platform-specific baseline for virtual test port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/virtual/flag/fast/test-expected.txt', 'foo') + MOCK_WEB_TESTS + 'platform/foo/virtual/flag/fast/test-expected.txt', 'foo') self.assertEqual(port.expected_baselines(virtual_test, '.txt'), - [('/mock-checkout/third_party/WebKit/LayoutTests/platform/foo', 'virtual/flag/fast/test-expected.txt')]) + [(MOCK_WEB_TESTS + 'platform/foo', 'virtual/flag/fast/test-expected.txt')]) self.assertEqual(port.expected_filename(virtual_test, '.txt', return_default=False), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/virtual/flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'platform/foo/virtual/flag/fast/test-expected.txt') self.assertEqual(port.expected_filename(virtual_test, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/virtual/flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'platform/foo/virtual/flag/fast/test-expected.txt') self.assertEqual(port.expected_filename(virtual_test, '.txt', return_default=False, fallback_base_for_virtual=False), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/virtual/flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'platform/foo/virtual/flag/fast/test-expected.txt') self.assertEqual(port.expected_filename(virtual_test, '.txt', fallback_base_for_virtual=False), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/virtual/flag/fast/test-expected.txt') + MOCK_WEB_TESTS + 'platform/foo/virtual/flag/fast/test-expected.txt') def test_additional_platform_directory(self): port = self.make_port(port_name='foo') port.FALLBACK_PATHS = {'': ['foo']} - port.host.filesystem.write_text_file('/mock-checkout/third_party/WebKit/LayoutTests/VirtualTestSuites', '[]') + port.host.filesystem.write_text_file(MOCK_WEB_TESTS + 'VirtualTestSuites', '[]') test_file = 'fast/test.html' # Simple additional platform directory @@ -266,7 +269,7 @@ [(None, 'fast/test-expected.txt')]) self.assertEqual(port.expected_filename(test_file, '.txt', return_default=False), None) self.assertEqual(port.expected_filename(test_file, '.txt'), - '/mock-checkout/third_party/WebKit/LayoutTests/fast/test-expected.txt') + MOCK_WEB_TESTS + 'fast/test-expected.txt') port.host.filesystem.write_text_file('/tmp/local-baselines/fast/test-expected.txt', 'foo') self.assertEqual(port.expected_baselines(test_file, '.txt'), @@ -291,23 +294,23 @@ def test_nonexistant_expectations(self): port = self.make_port(port_name='foo') - port.expectations_files = lambda: ['/mock-checkout/third_party/WebKit/LayoutTests/platform/exists/TestExpectations', - '/mock-checkout/third_party/WebKit/LayoutTests/platform/nonexistant/TestExpectations'] - port.host.filesystem.write_text_file('/mock-checkout/third_party/WebKit/LayoutTests/platform/exists/TestExpectations', '') + port.expectations_files = lambda: [MOCK_WEB_TESTS + 'platform/exists/TestExpectations', + MOCK_WEB_TESTS + 'platform/nonexistant/TestExpectations'] + port.host.filesystem.write_text_file(MOCK_WEB_TESTS + 'platform/exists/TestExpectations', '') self.assertEqual('\n'.join(port.expectations_dict().keys()), - '/mock-checkout/third_party/WebKit/LayoutTests/platform/exists/TestExpectations') + MOCK_WEB_TESTS + 'platform/exists/TestExpectations') def test_additional_expectations(self): port = self.make_port(port_name='foo') port.port_name = 'foo' port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/platform/foo/TestExpectations', '') + MOCK_WEB_TESTS + 'platform/foo/TestExpectations', '') port.host.filesystem.write_text_file( '/tmp/additional-expectations-1.txt', 'content1\n') port.host.filesystem.write_text_file( '/tmp/additional-expectations-2.txt', 'content2\n') port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/FlagExpectations/special-flag', 'content3') + MOCK_WEB_TESTS + 'FlagExpectations/special-flag', 'content3') self.assertEqual('\n'.join(port.expectations_dict().values()), '') @@ -330,21 +333,22 @@ port = self.make_port(port_name='foo') port.port_name = 'foo' port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/FlagExpectations/special-flag-a', 'aa') + MOCK_WEB_TESTS + 'FlagExpectations/special-flag-a', 'aa') port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/FlagExpectations/special-flag-b', 'bb') + MOCK_WEB_TESTS + 'FlagExpectations/special-flag-b', 'bb') port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/FlagExpectations/README.txt', 'cc') + MOCK_WEB_TESTS + 'FlagExpectations/README.txt', 'cc') self.assertEqual('\n'.join(port.expectations_dict().values()), '') - self.assertEqual('\n'.join(port.all_expectations_dict().values()), 'bb\naa') + # all_expectations_dict() is an OrderedDict, but its order depends on + # file system walking order. + self.assertEqual('\n'.join(sorted(port.all_expectations_dict().values())), 'aa\nbb') def test_flag_specific_expectations_identify_unreadable_file(self): port = self.make_port(port_name='foo') port.port_name = 'foo' - non_utf8_file = ('/mock-checkout/third_party/WebKit/LayoutTests/' - 'FlagExpectations/non-utf8-file') + non_utf8_file = MOCK_WEB_TESTS + 'FlagExpectations/non-utf8-file' invalid_utf8 = '\xC0' port.host.filesystem.write_binary_file(non_utf8_file, invalid_utf8) @@ -376,7 +380,7 @@ self.assertEqual(port_c.additional_driver_flags(), ['--cc'] + default_flags) - flag_file = '/mock-checkout/third_party/WebKit/LayoutTests/additional-driver-flag.setting' + flag_file = MOCK_WEB_TESTS + 'additional-driver-flag.setting' port_a.host.filesystem.write_text_file(flag_file, '--aa') port_b.host.filesystem.write_text_file(flag_file, '--aa') port_c.host.filesystem.write_text_file(flag_file, '--bb') @@ -907,7 +911,7 @@ # pylint: disable=protected-access port._options.image_first_tests = ['image-first', 'virtual/flag/additional-virtual-image-first'] port.host.filesystem.write_text_file( - '/mock-checkout/third_party/WebKit/LayoutTests/VirtualTestSuites', + MOCK_WEB_TESTS + 'VirtualTestSuites', json.dumps([ { "prefix": "flag", "base": "image-first", "args": ["--flag"]}, { "prefix": "flag", "base": "non-image-first", "args": ["--flag"]}
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py b/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py index 33b9ca2..97d5e74 100644 --- a/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py
@@ -39,6 +39,7 @@ from blinkpy.common import path_finder from blinkpy.common.host import Host from blinkpy.common.host_mock import MockHost +from blinkpy.common.path_finder import WEB_TESTS_LAST_COMPONENT from blinkpy.common.system.path import abspath_to_uri from blinkpy.common.system.system_host import SystemHost @@ -487,7 +488,7 @@ self.assertEqual(tests_run, ['passes/text.html']) def test_single_file_with_prefix(self): - tests_run = get_tests_run(['LayoutTests/passes/text.html']) + tests_run = get_tests_run([WEB_TESTS_LAST_COMPONENT + '/passes/text.html']) self.assertEqual(['passes/text.html'], tests_run) def test_stderr_is_saved(self): @@ -517,7 +518,7 @@ def test_test_list_with_prefix(self): host = MockHost() filename = '/tmp/foo.txt' - host.filesystem.write_text_file(filename, 'LayoutTests/passes/text.html') + host.filesystem.write_text_file(filename, WEB_TESTS_LAST_COMPONENT + '/passes/text.html') tests_run = get_tests_run(['--test-list=%s' % filename], host=host) self.assertEqual(['passes/text.html'], tests_run)
diff --git a/third_party/closure_compiler/externs/bookmark_manager_private.js b/third_party/closure_compiler/externs/bookmark_manager_private.js index ec1faf2..dfabdaf 100644 --- a/third_party/closure_compiler/externs/bookmark_manager_private.js +++ b/third_party/closure_compiler/externs/bookmark_manager_private.js
@@ -81,9 +81,10 @@ /** * Begins dragging a set of bookmarks * @param {Array} idList An array of string-valued ids + * @param {number} dragNodeIndex The index of the dragged node in |idList| * @param {boolean} isFromTouch True if the drag was initiated from touch */ -chrome.bookmarkManagerPrivate.startDrag = function(idList, isFromTouch) {}; +chrome.bookmarkManagerPrivate.startDrag = function(idList, dragNodeIndex, isFromTouch) {}; /** * Performs the drop action of the drag and drop session
diff --git a/third_party/closure_compiler/externs/developer_private.js b/third_party/closure_compiler/externs/developer_private.js index 54311a8..88f91de 100644 --- a/third_party/closure_compiler/externs/developer_private.js +++ b/third_party/closure_compiler/externs/developer_private.js
@@ -270,9 +270,25 @@ /** * @typedef {{ + * host: string, + * granted: boolean + * }} + */ +chrome.developerPrivate.SiteControl; + +/** + * @typedef {{ + * hasAllHosts: boolean, + * hosts: !Array<!chrome.developerPrivate.SiteControl> + * }} + */ +chrome.developerPrivate.SpecificSiteControls; + +/** + * @typedef {{ * simplePermissions: !Array<!chrome.developerPrivate.Permission>, * hostAccess: (!chrome.developerPrivate.HostAccess|undefined), - * runtimeHostPermissions: (!Array<string>|undefined) + * specificSiteControls: (!chrome.developerPrivate.SpecificSiteControls|undefined) * }} */ chrome.developerPrivate.Permissions;
diff --git a/third_party/feed/BUILD.gn b/third_party/feed/BUILD.gn index 798d3eb..589fab49 100644 --- a/third_party/feed/BUILD.gn +++ b/third_party/feed/BUILD.gn
@@ -32,10 +32,10 @@ "com.google.android.libraries.feed.sharedstream.publicapi.menumeasurer" } -android_resources("basicstream_internal_actions_resources") { - resource_dirs = [ "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/actions/res/" ] +android_resources("sharedstream_contextmenumanager_resources") { + resource_dirs = [ "src/src/main/java/com/google/android/libraries/feed/sharedstream/contextmenumanager/res" ] custom_package = - "com.google.android.libraries.feed.basicstream.internal.actions" + "com.google.android.libraries.feed.sharedstream.contextmenumanager" } android_library("feed_lib_java") { @@ -43,12 +43,12 @@ java_files = feed_lib_java_sources deps = [ - ":basicstream_internal_actions_resources", ":basicstream_internal_viewholders_resources", ":basicstream_resources", ":feed_lib_proto_java", ":piet_resources", ":shared_stream_publicapi_menumeasurer_resources", + ":sharedstream_contextmenumanager_resources", "//third_party/android_deps:android_support_annotations_java", "//third_party/android_deps:android_support_cardview_java", "//third_party/android_deps:android_support_v7_appcompat_java",
diff --git a/third_party/feed/README.chromium b/third_party/feed/README.chromium index 0aa68d1..1fcc48d 100644 --- a/third_party/feed/README.chromium +++ b/third_party/feed/README.chromium
@@ -2,7 +2,7 @@ Short name: feed URL: https://chromium.googlesource.com/feed Version: 0 -Revision: e291161061d18d222bc1b546225fe0567386cbf1 +Revision: 2cefe05b77f7039db95a63804edf284e68055dda License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/feed/java_sources.gni b/third_party/feed/java_sources.gni index 58fdb01..a7c31653 100644 --- a/third_party/feed/java_sources.gni +++ b/third_party/feed/java_sources.gni
@@ -72,7 +72,6 @@ "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/logging/VisibilityMonitor.java", "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/scroll/ScrollRestorer.java", "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/scroll/StreamScrollMonitor.java", - "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/util/ContextMenuHelper.java", "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/ContinuationViewHolder.java", "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/FeedViewHolder.java", "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/viewholders/HeaderViewHolder.java", @@ -95,6 +94,7 @@ "src/src/main/java/com/google/android/libraries/feed/common/functional/Predicate.java", "src/src/main/java/com/google/android/libraries/feed/common/functional/SettableSupplier.java", "src/src/main/java/com/google/android/libraries/feed/common/functional/Supplier.java", + "src/src/main/java/com/google/android/libraries/feed/common/locale/LocaleUtils.java", "src/src/main/java/com/google/android/libraries/feed/common/logging/Dumpable.java", "src/src/main/java/com/google/android/libraries/feed/common/logging/Dumper.java", "src/src/main/java/com/google/android/libraries/feed/common/logging/Logger.java", @@ -128,6 +128,7 @@ "src/src/main/java/com/google/android/libraries/feed/feedprotocoladapter/internal/transformers/DataOperationTransformer.java", "src/src/main/java/com/google/android/libraries/feed/feedprotocoladapter/internal/transformers/FeatureDataOperationTransformer.java", "src/src/main/java/com/google/android/libraries/feed/feedrequestmanager/FeedRequestManager.java", + "src/src/main/java/com/google/android/libraries/feed/feedrequestmanager/internal/Utils.java", "src/src/main/java/com/google/android/libraries/feed/feedsessionmanager/FeedSessionManager.java", "src/src/main/java/com/google/android/libraries/feed/feedsessionmanager/FeedSessionManagerFactory.java", "src/src/main/java/com/google/android/libraries/feed/feedsessionmanager/internal/ContentCache.java", @@ -156,6 +157,7 @@ "src/src/main/java/com/google/android/libraries/feed/feedstore/internal/PersistentFeedStore.java", "src/src/main/java/com/google/android/libraries/feed/host/action/ActionApi.java", "src/src/main/java/com/google/android/libraries/feed/host/action/StreamActionApi.java", + "src/src/main/java/com/google/android/libraries/feed/host/config/ApplicationInfo.java", "src/src/main/java/com/google/android/libraries/feed/host/config/Configuration.java", "src/src/main/java/com/google/android/libraries/feed/host/config/DebugBehavior.java", "src/src/main/java/com/google/android/libraries/feed/host/imageloader/BundledAssets.java", @@ -230,9 +232,8 @@ "src/src/main/java/com/google/android/libraries/feed/piet/host/HostBindingProvider.java", "src/src/main/java/com/google/android/libraries/feed/piet/ui/DrawableScalingHelper.java", "src/src/main/java/com/google/android/libraries/feed/piet/ui/GridRowView.java", - "src/src/main/java/com/google/android/libraries/feed/piet/ui/RoundedCornerColorDrawable.java", - "src/src/main/java/com/google/android/libraries/feed/piet/ui/RoundedCornerImageView.java", - "src/src/main/java/com/google/android/libraries/feed/piet/ui/RoundedCornerViewHelper.java", + "src/src/main/java/com/google/android/libraries/feed/piet/ui/RoundedCornerWrapperView.java", + "src/src/main/java/com/google/android/libraries/feed/sharedstream/contextmenumanager/ContextMenuManager.java", "src/src/main/java/com/google/android/libraries/feed/sharedstream/offlinemonitor/StreamOfflineMonitor.java", "src/src/main/java/com/google/android/libraries/feed/sharedstream/piet/PietAssetProvider.java", "src/src/main/java/com/google/android/libraries/feed/sharedstream/piet/PietCustomElementProvider.java",
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium index 5682574..f48e3b3 100644 --- a/third_party/libaom/README.chromium +++ b/third_party/libaom/README.chromium
@@ -2,9 +2,9 @@ Short Name: libaom URL: https://aomedia.googlesource.com/aom/ Version: 0 -Date: Tuesday September 18 2018 +Date: Monday October 08 2018 Branch: master -Commit: f866f5ebb34b22afc2244789dc8551b0c8d99a13 +Commit: a5078bf8d0e7c01eab670cfc1cfe7b9fb065e931 License: BSD License File: source/libaom/LICENSE Security Critical: yes
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h index ed07851..acf6f27 100644 --- a/third_party/libaom/source/config/config/aom_version.h +++ b/third_party/libaom/source/config/config/aom_version.h
@@ -12,8 +12,8 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 0 #define VERSION_PATCH 0 -#define VERSION_EXTRA "612-gf866f5ebb" +#define VERSION_EXTRA "614-ga5078bf8d" #define VERSION_PACKED \ ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH)) -#define VERSION_STRING_NOSP "1.0.0-612-gf866f5ebb" -#define VERSION_STRING " 1.0.0-612-gf866f5ebb" +#define VERSION_STRING_NOSP "1.0.0-614-ga5078bf8d" +#define VERSION_STRING " 1.0.0-614-ga5078bf8d"
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium index a17246a..baabfbd 100644 --- a/third_party/libvpx/README.chromium +++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@ License File: source/libvpx/LICENSE Security Critical: yes -Date: Saturday September 29 2018 +Date: Monday October 08 2018 Branch: master -Commit: 2beb5c9f91e7166c2c9d01c94bf84767815121e4 +Commit: ecc31d28781c490f5fb18a3e6873692a1b8e6cea Description: Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h index 81961788..6ae53f6 100644 --- a/third_party/libvpx/source/config/vpx_version.h +++ b/third_party/libvpx/source/config/vpx_version.h
@@ -2,7 +2,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 7 #define VERSION_PATCH 0 -#define VERSION_EXTRA "1115-g2beb5c9f9" +#define VERSION_EXTRA "1139-gecc31d287" #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) -#define VERSION_STRING_NOSP "v1.7.0-1115-g2beb5c9f9" -#define VERSION_STRING " v1.7.0-1115-g2beb5c9f9" +#define VERSION_STRING_NOSP "v1.7.0-1139-gecc31d287" +#define VERSION_STRING " v1.7.0-1139-gecc31d287"
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer.cc b/tools/ipc_fuzzer/fuzzer/fuzzer.cc index ec291e5..af3ba548 100644 --- a/tools/ipc_fuzzer/fuzzer/fuzzer.cc +++ b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
@@ -1172,19 +1172,6 @@ }; template <> -struct FuzzTraits<media::VideoCaptureFormat> { - static bool Fuzz(media::VideoCaptureFormat* p, Fuzzer* fuzzer) { - if (!FuzzParam(&p->frame_size, fuzzer)) - return false; - if (!FuzzParam(&p->frame_rate, fuzzer)) - return false; - if (!FuzzParam(reinterpret_cast<int*>(&p->pixel_format), fuzzer)) - return false; - return true; - } -}; - -template <> struct FuzzTraits<net::LoadTimingInfo> { static bool Fuzz(net::LoadTimingInfo* p, Fuzzer* fuzzer) { return FuzzParam(&p->socket_log_id, fuzzer) &&
diff --git a/tools/linux/dump-static-initializers.py b/tools/linux/dump-static-initializers.py index b71d062..e937d68 100755 --- a/tools/linux/dump-static-initializers.py +++ b/tools/linux/dump-static-initializers.py
@@ -38,8 +38,10 @@ IS_GIT_WORKSPACE = (subprocess.Popen( ['git', 'rev-parse'], stderr=subprocess.PIPE).wait() == 0) + class Demangler(object): """A wrapper around c++filt to provide a function to demangle symbols.""" + def __init__(self, toolchain): self.cppfilt = subprocess.Popen([toolchain + 'c++filt'], stdin=subprocess.PIPE, @@ -50,6 +52,7 @@ self.cppfilt.stdin.write(sym + '\n') return self.cppfilt.stdout.readline().strip() + # Matches for example: "cert_logger.pb.cc", capturing "cert_logger". protobuf_filename_re = re.compile(r'(.*)\.pb\.cc$') def QualifyFilenameAsProto(filename): @@ -72,6 +75,7 @@ candidate = line.strip() return candidate + # Regex matching the substring of a symbol's demangled text representation most # likely to appear in a source file. # Example: "v8::internal::Builtins::InitBuiltinFunctionTable()" becomes @@ -99,6 +103,7 @@ candidate = line.strip() return candidate + # Regex matching nm output for the symbols we're interested in. # See test_ParseNmLine for examples. nm_re = re.compile(r'(\S+) (\S+) t (?:_ZN12)?_GLOBAL__(?:sub_)?I_(.*)') @@ -123,6 +128,7 @@ '_GLOBAL__sub_I_extension_specifics.pb.cc') assert parse == ('extension_specifics.pb.cc', 40607408, 36), parse + # Just always run the test; it is fast enough. test_ParseNmLine() @@ -136,6 +142,7 @@ if parse: yield parse + # Regex matching objdump output for the symbols we're interested in. # Example line: # 12354ab: (disassembly, including <FunctionReference>) @@ -158,13 +165,14 @@ if ref.startswith('.LC') or ref.startswith('_DYNAMIC'): # Ignore these, they are uninformative. continue - if ref.startswith('_GLOBAL__I_'): + if re.match('_GLOBAL__(?:sub_)?I_', ref): # Probably a relative jump within this function. continue refs.add(ref) return sorted(refs) + def main(): parser = optparse.OptionParser(usage='%prog [option] filename') parser.add_option('-d', '--diffable', dest='diffable', @@ -236,5 +244,6 @@ return 0 + if '__main__' == __name__: sys.exit(main())
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index faa2bb4c..9a62862a4 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -395,18 +395,8 @@ }, 'chromium.perf.fyi': { - # TODO(crbug.com/828445): Remove 'Linux Compile Perf FYI' - 'Linux Compile Perf FYI': 'official_goma_perf', - # TODO(crbug.com/828444): Remove 'Android Builder Perf FYI' - 'Android Builder Perf FYI': 'official_goma_minimal_symbols_android', - # TODO(crbug.com/828442): Remove 'Android arm64 Builder Perf FYI' - 'Android arm64 Builder Perf FYI': 'official_goma_minimal_symbols_android_arm64', - 'Android CFI Builder Perf FYI': 'official_goma_minimal_symbols_android_thin_lto_opt', - 'Android CFI arm64 Builder Perf FYI': 'official_goma_minimal_symbols_android_thin_lto_opt_arm64', - # TODO(crbug.com/828443): Remove 'Mac Builder Perf FYI' - 'Mac Builder Perf FYI': 'official_goma', - # TODO(crbug.com/835288): Remove 'Win Builder Perf FYI' - 'Win Builder Perf FYI': 'official_goma_x86', + 'android-cfi-builder-perf-fyi': 'official_goma_minimal_symbols_android_thin_lto_opt', + 'android_arm64-cfi-builder-perf-fyi': 'official_goma_minimal_symbols_android_thin_lto_opt_arm64', }, 'chromium.swarm': { @@ -709,6 +699,10 @@ 'win_chrome_official': 'official_goma_x86', }, + 'tryserver.chrome.win': { + 'win_chrome_official': 'official_goma_x86', + }, + 'tryserver.v8': { 'v8_linux_blink_rel': 'release_trybot', 'v8_linux_chromium_gn_rel': 'release_trybot',
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 93404b06..9c28d79 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -1647,6 +1647,18 @@ </description> </action> +<action name="Android.ExploreSitesNTP.Opened"> + <owner>dimich@chromium.org</owner> + <description>User opened NTP with enabled ExploreSites section.</description> +</action> + +<action name="Android.ExploreSitesPage.Open"> + <owner>dimich@chromium.org</owner> + <description> + User opened ExploreSites page, typically by clicking on a NTP category icon. + </description> +</action> + <action name="Android.HistoryPage.ClearBrowsingData"> <owner>twellington@chromium.org</owner> <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index a9119d595..976710e 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -29309,6 +29309,7 @@ <int value="-726892130" label="AndroidMessagesIntegration:disabled"/> <int value="-723224470" label="enable-password-force-saving:enabled"/> <int value="-722474177" label="browser-side-navigation:disabled"/> + <int value="-721245076" label="DesktopPWAsStayInWindow:disabled"/> <int value="-719819631" label="TranslateUI:disabled"/> <int value="-719147284" label="ExperimentalProductivityFeatures:disabled"/> <int value="-718884399" label="NewTabPageUIMd:enabled"/> @@ -29607,6 +29608,7 @@ <int value="-102537270" label="extension-content-verification"/> <int value="-102227288" label="PasswordExport:disabled"/> <int value="-99781021" label="disable-roboto-font-ui"/> + <int value="-97145978" label="DesktopPWAsStayInWindow:enabled"/> <int value="-89690053" label="MaterialDesignUserManager:enabled"/> <int value="-88822940" label="ssl-version-min"/> <int value="-88273414" label="ContentSuggestionsShowSummary:enabled"/> @@ -29857,6 +29859,7 @@ <int value="412957264" label="tab-close-buttons-hidden-with-touch"/> <int value="413081240" label="enable-new-md-input-view"/> <int value="413695227" label="NTPSuggestionsStandaloneUI:enabled"/> + <int value="414114078" label="LitePageServerPreviews:disabled"/> <int value="415154056" label="enable-physical-keyboard-autocorrect"/> <int value="416887895" label="enable-password-change-support"/> <int value="417709910" @@ -29988,6 +29991,7 @@ <int value="664591021" label="EnableContinueReading:enabled"/> <int value="665409384" label="AutofillToolkitViewsCreditCardDialogsMac:enabled"/> + <int value="667643314" label="LitePageServerPreviews:enabled"/> <int value="673588373" label="OmniboxPedalSuggestions:disabled"/> <int value="679931272" label="DcheckIsFatal:enabled"/> <int value="680070635" @@ -33882,6 +33886,7 @@ <int value="177" label="SSL_CLIENT_AUTH_NO_COMMON_ALGORITHMS"/> <int value="178" label="EARLY_DATA_REJECTED"/> <int value="179" label="WRONG_VERSION_ON_EARLY_DATA"/> + <int value="180" label="TLS13_DOWNGRADE_DETECTED"/> <int value="200" label="CERT_COMMON_NAME_INVALID"/> <int value="201" label="CERT_DATE_INVALID"/> <int value="202" label="CERT_AUTHORITY_INVALID"/> @@ -40685,6 +40690,7 @@ <int value="2" label="Subframe navigation"/> <int value="3" label="Server Unavailable"/> <int value="4" label="Infobar hasn't been seen by the user and needs to be"/> + <int value="5" label="Network was not slow"/> </enum> <enum name="PreviewsServerLitePageServerResponse">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 54daefa..0ed79ba 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -11176,6 +11176,18 @@ </summary> </histogram> +<histogram name="BrowserRenderProcessHost.InvisibleMediaStreamFrameDepth" + units="frame_depth" expires_after="M72"> + <owner>boliu@chromium.org</owner> + <owner>alexmos@chromium.org</owner> + <summary> + Recorded at most once per renderer process when it first becomes invisible + and has media stream. Record the frame depth of the process. Note this + metric is only meaningful when some form of OOPIF is enabled; otherwise + frame depth is always 0. + </summary> +</histogram> + <histogram name="BrowserRenderProcessHost.KeepAliveDuration" units="ms"> <owner>horo@chromium.org</owner> <summary> @@ -27875,6 +27887,15 @@ </summary> </histogram> +<histogram name="ExploreSites.ClickedNTPCategoryIndex"> + <owner>dimich@chromium.org</owner> + <summary> + 0-based index of a category tile on NTP which was clicked by the user. + Indices are assigned by counting category tiles left-to-right, top-to-bottom + as they appear on NTP. Recorded on click. + </summary> +</histogram> + <histogram name="ExploreSites.ExploreSitesStore.StoreEvent" enum="ExploreSitesStoreEvent"> <owner>dewittj@chromium.org</owner> @@ -27892,6 +27913,15 @@ </summary> </histogram> +<histogram name="ExploreSites.NTPLoadingCatalogFromNetwork" units="Boolean"> + <owner>dimich@chromium.org</owner> + <summary> + Recorded every time NTP is opened while ExploreSites feature is enabled. + Indicates whether or not the local cached version of ExploreSites catalog + was available or a network request was initiated to load one. + </summary> +</histogram> + <histogram name="ExtensionActivity.AdInjected" units="Extension Count"> <obsolete> Deprecated with M46. @@ -81551,6 +81581,22 @@ </summary> </histogram> +<histogram name="Printing.CUPS.JobDuration.JobCancelled" units="ms"> + <owner>jschettler@chromium.org</owner> + <summary> + Records the print job duration of a cancelled print job. Includes time spent + in a suspended or error state. Only recorded on Chrome OS. + </summary> +</histogram> + +<histogram name="Printing.CUPS.JobDuration.JobDone" units="ms"> + <owner>jschettler@chromium.org</owner> + <summary> + Records the print job duration of a done/completed print job. Includes time + spent in a suspended or error state. Only recorded on Chrome OS. + </summary> +</histogram> + <histogram name="Printing.CUPS.JobResult" enum="PrintJobResult"> <owner>skau@chromium.org</owner> <summary> @@ -81568,6 +81614,14 @@ </summary> </histogram> +<histogram name="Printing.CUPS.PrintDocumentSize" units="KB"> + <owner>jschettler@chromium.org</owner> + <summary> + Records the total size of the printed document (PDF) sent to CUPS. Only + recorded on Chrome OS. + </summary> +</histogram> + <histogram name="Printing.CUPS.PrinterAdded" enum="PrinterProtocol"> <owner>skau@chromium.org</owner> <summary>
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 6df3e546..5450883 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -366,3 +366,9 @@ crbug.com/853835 [ Linux ] loading.desktop.network_service/Kenh14_warm [ Skip ] crbug.com/853835 [ Linux ] loading.desktop.network_service/Taobao_cold [ Skip ] crbug.com/853835 [ Linux ] loading.desktop.network_service/Taobao_warm [ Skip ] +crbug.com/879833 [ Linux ] loading.desktop.network_service/Walgreens_cold [ Skip ] +crbug.com/879833 [ Linux ] loading.desktop.network_service/Walgreens_warm [ Skip ] + +# Benchmark: loading.desktop_layout_ng +crbug.com/879833 [ Linux ] loading.desktop_layout_ng/Walgreens_cold [ Skip ] +crbug.com/879833 [ Linux ] loading.desktop_layout_ng/Walgreens_warm [ Skip ]
diff --git a/tools/perf_expectations/OWNERS b/tools/perf_expectations/OWNERS deleted file mode 100644 index 514cf031..0000000 --- a/tools/perf_expectations/OWNERS +++ /dev/null
@@ -1,3 +0,0 @@ -jochen@chromium.org -thakis@chromium.org -thestig@chromium.org
diff --git a/tools/perf_expectations/PRESUBMIT.py b/tools/perf_expectations/PRESUBMIT.py deleted file mode 100644 index 6c7768f..0000000 --- a/tools/perf_expectations/PRESUBMIT.py +++ /dev/null
@@ -1,44 +0,0 @@ -# Copyright (c) 2011 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. - -"""Presubmit script for perf_expectations. - -See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for -details on the presubmit API built into depot_tools. -""" - -PERF_EXPECTATIONS = 'tools/perf_expectations/perf_expectations.json' -CONFIG_FILE = 'tools/perf_expectations/chromium_perf_expectations.cfg' - -def CheckChangeOnUpload(input_api, output_api): - run_tests = False - for path in input_api.LocalPaths(): - path = path.replace('\\', '/') - if (PERF_EXPECTATIONS == path or CONFIG_FILE == path): - run_tests = True - - output = [] - if run_tests: - whitelist = [r'.+_unittest\.py$'] - output.extend(input_api.canned_checks.RunUnitTestsInDirectory( - input_api, output_api, 'tests', whitelist)) - return output - - -def CheckChangeOnCommit(input_api, output_api): - run_tests = False - for path in input_api.LocalPaths(): - path = path.replace('\\', '/') - if (PERF_EXPECTATIONS == path or CONFIG_FILE == path): - run_tests = True - - output = [] - if run_tests: - whitelist = [r'.+_unittest\.py$'] - output.extend(input_api.canned_checks.RunUnitTestsInDirectory( - input_api, output_api, 'tests', whitelist)) - - output.extend(input_api.canned_checks.CheckDoNotSubmit(input_api, - output_api)) - return output
diff --git a/tools/perf_expectations/README.txt b/tools/perf_expectations/README.txt deleted file mode 100644 index cd8f3d5..0000000 --- a/tools/perf_expectations/README.txt +++ /dev/null
@@ -1,24 +0,0 @@ -This is where old perf machinery used to live, keeping track of binary sizes, -etc. Now that lives elsewhere and has a team to support it (see -https://www.chromium.org/developers/tree-sheriffs/perf-sheriffs). This code -remains to ensure that no static initializers get into Chromium. - -Because this code has this history, it's far more complicated than it needs to -be. TODO(dpranke): Simplify it. https://crbug.com/572393 - -In the meanwhile, if you're trying to update perf_expectations.json, there are -no instructions for doing so, and the tools that you used to use don't work -because they rely on data files that were last updated at the end of 2015. So -here's what to do to reset the expected static initializer count value. - -The expected static initializer count value is in the "regress" field for the -platform. In addition, each platform has a checksum in the "sha1" field to -ensure that you properly used the magic tools. Since the magic tools don't work -anymore, dpranke added a bypass to the verification. If you run: - -> tools/perf_expectations/make_expectations.py --checksum --verbose - -the script will tell you what the checksum *should* be. Alter the "sha1" field -to be that value, and you can commit changes to that file. - -Please see https://crbug.com/572393 for more information.
diff --git a/tools/perf_expectations/chromium_perf_expectations.cfg b/tools/perf_expectations/chromium_perf_expectations.cfg deleted file mode 100644 index 4d3abe7..0000000 --- a/tools/perf_expectations/chromium_perf_expectations.cfg +++ /dev/null
@@ -1,4 +0,0 @@ -{ - "base_url": "http://build.chromium.org/f/chromium/perf", - "perf_file": "perf_expectations.json" -}
diff --git a/tools/perf_expectations/make_expectations.py b/tools/perf_expectations/make_expectations.py deleted file mode 100755 index 996d78a..0000000 --- a/tools/perf_expectations/make_expectations.py +++ /dev/null
@@ -1,383 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# For instructions see: -# http://www.chromium.org/developers/tree-sheriffs/perf-sheriffs - -import hashlib -import math -import optparse -import os -import re -import subprocess -import sys -import time -import urllib2 - - -try: - import json -except ImportError: - import simplejson as json - - -__version__ = '1.0' -EXPECTATIONS_DIR = os.path.dirname(os.path.abspath(__file__)) -DEFAULT_CONFIG_FILE = os.path.join(EXPECTATIONS_DIR, - 'chromium_perf_expectations.cfg') -DEFAULT_TOLERANCE = 0.05 -USAGE = '' - - -def ReadFile(filename): - try: - file = open(filename, 'rb') - except IOError, e: - print >> sys.stderr, ('I/O Error reading file %s(%s): %s' % - (filename, e.errno, e.strerror)) - raise e - contents = file.read() - file.close() - return contents - - -def ConvertJsonIntoDict(string): - """Read a JSON string and convert its contents into a Python datatype.""" - if len(string) == 0: - print >> sys.stderr, ('Error could not parse empty string') - raise Exception('JSON data missing') - - try: - jsondata = json.loads(string) - except ValueError, e: - print >> sys.stderr, ('Error parsing string: "%s"' % string) - raise e - return jsondata - - -# Floating point representation of last time we fetched a URL. -last_fetched_at = None -def FetchUrlContents(url): - global last_fetched_at - if last_fetched_at and ((time.time() - last_fetched_at) <= 0.5): - # Sleep for half a second to avoid overloading the server. - time.sleep(0.5) - try: - last_fetched_at = time.time() - connection = urllib2.urlopen(url) - except urllib2.HTTPError, e: - if e.code == 404: - return None - raise e - text = connection.read().strip() - connection.close() - return text - - -def GetRowData(data, key): - rowdata = [] - # reva and revb always come first. - for subkey in ['reva', 'revb']: - if subkey in data[key]: - rowdata.append('"%s": %s' % (subkey, data[key][subkey])) - # Strings, like type, come next. - for subkey in ['type', 'better']: - if subkey in data[key]: - rowdata.append('"%s": "%s"' % (subkey, data[key][subkey])) - # Finally the main numbers come last. - for subkey in ['improve', 'regress', 'tolerance']: - if subkey in data[key]: - rowdata.append('"%s": %s' % (subkey, data[key][subkey])) - return rowdata - - -def GetRowDigest(rowdata, key): - sha1 = hashlib.sha1() - rowdata = [str(possibly_unicode_string).encode('ascii') - for possibly_unicode_string in rowdata] - sha1.update(str(rowdata) + key) - return sha1.hexdigest()[0:8] - - -def WriteJson(filename, data, keys, calculate_sha1=True): - """Write a list of |keys| in |data| to the file specified in |filename|.""" - try: - file = open(filename, 'wb') - except IOError, e: - print >> sys.stderr, ('I/O Error writing file %s(%s): %s' % - (filename, e.errno, e.strerror)) - return False - jsondata = [] - for key in keys: - rowdata = GetRowData(data, key) - if calculate_sha1: - # Include an updated checksum. - rowdata.append('"sha1": "%s"' % GetRowDigest(rowdata, key)) - else: - if 'sha1' in data[key]: - rowdata.append('"sha1": "%s"' % (data[key]['sha1'])) - jsondata.append('"%s": {%s}' % (key, ', '.join(rowdata))) - jsondata.append('"load": true') - jsontext = '{%s\n}' % ',\n '.join(jsondata) - file.write(jsontext + '\n') - file.close() - return True - - -def FloatIsInt(f): - epsilon = 1.0e-10 - return abs(f - int(f)) <= epsilon - - -last_key_printed = None -def Main(args): - def OutputMessage(message, verbose_message=True): - global last_key_printed - if not options.verbose and verbose_message: - return - - if key != last_key_printed: - last_key_printed = key - print '\n' + key + ':' - print ' %s' % message - - parser = optparse.OptionParser(usage=USAGE, version=__version__) - parser.add_option('-v', '--verbose', action='store_true', default=False, - help='enable verbose output') - parser.add_option('-s', '--checksum', action='store_true', - help='test if any changes are pending') - parser.add_option('-c', '--config', dest='config_file', - default=DEFAULT_CONFIG_FILE, - help='set the config file to FILE', metavar='FILE') - options, args = parser.parse_args(args) - - if options.verbose: - print 'Verbose output enabled.' - - config = ConvertJsonIntoDict(ReadFile(options.config_file)) - - # Get the list of summaries for a test. - base_url = config['base_url'] - # Make the perf expectations file relative to the path of the config file. - perf_file = os.path.join( - os.path.dirname(options.config_file), config['perf_file']) - perf = ConvertJsonIntoDict(ReadFile(perf_file)) - - # Fetch graphs.dat for this combination. - perfkeys = perf.keys() - # In perf_expectations.json, ignore the 'load' key. - perfkeys.remove('load') - perfkeys.sort() - - write_new_expectations = False - found_checksum_mismatch = False - for key in perfkeys: - value = perf[key] - tolerance = value.get('tolerance', DEFAULT_TOLERANCE) - better = value.get('better', None) - - # Verify the checksum. - original_checksum = value.get('sha1', '') - if 'sha1' in value: - del value['sha1'] - rowdata = GetRowData(perf, key) - computed_checksum = GetRowDigest(rowdata, key) - if original_checksum == computed_checksum: - OutputMessage('checksum matches, skipping') - continue - elif options.checksum: - OutputMessage('checksum mismatch, original = %s, computed = %s' % - (original_checksum, computed_checksum)) - found_checksum_mismatch = True - continue - - # Skip expectations that are missing a reva or revb. We can't generate - # expectations for those. - if not(value.has_key('reva') and value.has_key('revb')): - OutputMessage('missing revision range, skipping') - continue - revb = int(value['revb']) - reva = int(value['reva']) - - # Ensure that reva is less than revb. - if reva > revb: - temp = reva - reva = revb - revb = temp - - # Get the system/test/graph/tracename and reftracename for the current key. - matchData = re.match(r'^([^/]+)\/([^/]+)\/([^/]+)\/([^/]+)$', key) - if not matchData: - OutputMessage('cannot parse key, skipping') - continue - system = matchData.group(1) - test = matchData.group(2) - graph = matchData.group(3) - tracename = matchData.group(4) - reftracename = tracename + '_ref' - - # Create the summary_url and get the json data for that URL. - # FetchUrlContents() may sleep to avoid overloading the server with - # requests. - summary_url = '%s/%s/%s/%s-summary.dat' % (base_url, system, test, graph) - summaryjson = FetchUrlContents(summary_url) - if not summaryjson: - OutputMessage('ERROR: cannot find json data, please verify', - verbose_message=False) - return 0 - - # Set value's type to 'relative' by default. - value_type = value.get('type', 'relative') - - summarylist = summaryjson.split('\n') - trace_values = {} - traces = [tracename] - if value_type == 'relative': - traces += [reftracename] - for trace in traces: - trace_values.setdefault(trace, {}) - - # Find the high and low values for each of the traces. - scanning = False - for line in summarylist: - jsondata = ConvertJsonIntoDict(line) - try: - rev = int(jsondata['rev']) - except ValueError: - print ('Warning: skipping rev %r because could not be parsed ' - 'as an integer.' % jsondata['rev']) - continue - if rev <= revb: - scanning = True - if rev < reva: - break - - # We found the upper revision in the range. Scan for trace data until we - # find the lower revision in the range. - if scanning: - for trace in traces: - if trace not in jsondata['traces']: - OutputMessage('trace %s missing' % trace) - continue - if type(jsondata['traces'][trace]) != type([]): - OutputMessage('trace %s format not recognized' % trace) - continue - try: - tracevalue = float(jsondata['traces'][trace][0]) - except ValueError: - OutputMessage('trace %s value error: %s' % ( - trace, str(jsondata['traces'][trace][0]))) - continue - - for bound in ['high', 'low']: - trace_values[trace].setdefault(bound, tracevalue) - - trace_values[trace]['high'] = max(trace_values[trace]['high'], - tracevalue) - trace_values[trace]['low'] = min(trace_values[trace]['low'], - tracevalue) - - if 'high' not in trace_values[tracename]: - OutputMessage('no suitable traces matched, skipping') - continue - - if value_type == 'relative': - # Calculate assuming high deltas are regressions and low deltas are - # improvements. - regress = (float(trace_values[tracename]['high']) - - float(trace_values[reftracename]['low'])) - improve = (float(trace_values[tracename]['low']) - - float(trace_values[reftracename]['high'])) - elif value_type == 'absolute': - # Calculate assuming high absolutes are regressions and low absolutes are - # improvements. - regress = float(trace_values[tracename]['high']) - improve = float(trace_values[tracename]['low']) - - # So far we've assumed better is lower (regress > improve). If the actual - # values for regress and improve are equal, though, and better was not - # specified, alert the user so we don't let them create a new file with - # ambiguous rules. - if better == None and regress == improve: - OutputMessage('regress (%s) is equal to improve (%s), and "better" is ' - 'unspecified, please fix by setting "better": "lower" or ' - '"better": "higher" in this perf trace\'s expectation' % ( - regress, improve), verbose_message=False) - return 1 - - # If the existing values assume regressions are low deltas relative to - # improvements, swap our regress and improve. This value must be a - # scores-like result. - if 'regress' in perf[key] and 'improve' in perf[key]: - if perf[key]['regress'] < perf[key]['improve']: - assert(better != 'lower') - better = 'higher' - temp = regress - regress = improve - improve = temp - else: - # Sometimes values are equal, e.g., when they are both 0, - # 'better' may still be set to 'higher'. - assert(better != 'higher' or - perf[key]['regress'] == perf[key]['improve']) - better = 'lower' - - # If both were ints keep as int, otherwise use the float version. - originally_ints = False - if FloatIsInt(regress) and FloatIsInt(improve): - originally_ints = True - - if better == 'higher': - if originally_ints: - regress = int(math.floor(regress - abs(regress*tolerance))) - improve = int(math.ceil(improve + abs(improve*tolerance))) - else: - regress = regress - abs(regress*tolerance) - improve = improve + abs(improve*tolerance) - else: - if originally_ints: - improve = int(math.floor(improve - abs(improve*tolerance))) - regress = int(math.ceil(regress + abs(regress*tolerance))) - else: - improve = improve - abs(improve*tolerance) - regress = regress + abs(regress*tolerance) - - # Calculate the new checksum to test if this is the only thing that may have - # changed. - checksum_rowdata = GetRowData(perf, key) - new_checksum = GetRowDigest(checksum_rowdata, key) - - if ('regress' in perf[key] and 'improve' in perf[key] and - perf[key]['regress'] == regress and perf[key]['improve'] == improve and - original_checksum == new_checksum): - OutputMessage('no change') - continue - - write_new_expectations = True - OutputMessage('traces: %s' % trace_values, verbose_message=False) - OutputMessage('before: %s' % perf[key], verbose_message=False) - perf[key]['regress'] = regress - perf[key]['improve'] = improve - OutputMessage('after: %s' % perf[key], verbose_message=False) - - if options.checksum: - if found_checksum_mismatch: - return 1 - else: - return 0 - - if write_new_expectations: - print '\nWriting expectations... ', - WriteJson(perf_file, perf, perfkeys) - print 'done' - else: - if options.verbose: - print '' - print 'No changes.' - return 0 - - -if __name__ == '__main__': - sys.exit(Main(sys.argv))
diff --git a/tools/perf_expectations/perf_expectations.json b/tools/perf_expectations/perf_expectations.json deleted file mode 100644 index bf071330..0000000 --- a/tools/perf_expectations/perf_expectations.json +++ /dev/null
@@ -1,9 +0,0 @@ -{"linux-release-64/sizes/chrome-si/initializers": {"reva": 480969, "revb": 480969, "type": "absolute", "better": "lower", "improve": 8, "regress": 8, "tolerance": 0, "sha1": "3c815259"}, - "linux-release-64/sizes/nacl_helper-si/initializers": {"reva": 480969, "revb": 480969, "type": "absolute", "better": "lower", "improve": 6, "regress": 8, "sha1": "8416f450"}, - "linux-release-64/sizes/nacl_helper_bootstrap-si/initializers": {"reva": 114822, "revb": 115019, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "228221af"}, - "linux-release/sizes/chrome-si/initializers": {"reva": 480969, "revb": 480969, "type": "absolute", "better": "lower", "improve": 9, "regress": 9, "tolerance": 0, "sha1": "03dc3cfd"}, - "linux-release/sizes/nacl_helper-si/initializers": {"reva": 480969, "revb": 480969, "type": "absolute", "better": "lower", "improve": 7, "regress": 9, "sha1": "1a3c5b2b"}, - "linux-release/sizes/nacl_helper_bootstrap-si/initializers": {"reva": 114822, "revb": 115019, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "dd908f29"}, - "mac-release/sizes/chrome-si/initializers": {"reva": 281731, "revb": 281731, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "tolerance": 0, "sha1": "01759b7f"}, - "load": true -}
diff --git a/tools/perf_expectations/sample_test_cases.json b/tools/perf_expectations/sample_test_cases.json deleted file mode 100644 index 0fb7462..0000000 --- a/tools/perf_expectations/sample_test_cases.json +++ /dev/null
@@ -1,28 +0,0 @@ -{"linux-release/media_tests_av_perf/audio_latency/latency": {"reva": 180005, "revb": 180520, "type": "absolute", "better": "lower", "improve": 190, "regress": 222, "sha1": "fc9815d5"}, -"linux-release/media_tests_av_perf/dropped_fps/tulip2.wav": {"reva": 181131, "revb": 181572, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "fb8157f9"}, -"linux-release/media_tests_av_perf/dropped_fps/tulip2.webm": {"reva": 181131, "revb": 181572, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "c0fb3421"}, -"linux-release/media_tests_av_perf/dropped_frames/crowd1080.webm": {"reva": 181131, "revb": 181572, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "fa9582d3"}, -"linux-release/media_tests_av_perf/dropped_frames/crowd2160.webm": {"reva": 181131, "revb": 181572, "type": "absolute", "better": "lower", "improve": 166, "regress": 231, "sha1": "ca3a7a47"}, -"linux-release/media_tests_av_perf/fps/tulip2.m4a": {"reva": 34239, "revb": 1298213, "type": "absolute", "better": "higher", "improve": 0, "regress": 0}, -"linux-release/media_tests_av_perf/fps/tulip2.mp3": {"reva": 34239, "revb": 1298213, "type": "absolute", "better": "higher", "improve": 0, "regress": 0}, -"linux-release/media_tests_av_perf/fps/tulip2.mp4": {"reva": 34239, "revb": 1298213, "type": "absolute", "better": "higher", "improve": 32, "regress": 28}, -"linux-release/media_tests_av_perf/fps/tulip2.ogg": {"reva": 34239, "revb": 1298213, "type": "absolute", "better": "higher", "improve": 0, "regress": 0}, -"linux-release/media_tests_av_perf/fps/tulip2.ogv": {"reva": 34239, "revb": 1298213, "type": "absolute", "better": "higher", "improve": 32, "regress": 28}, -"linux-release/media_tests_av_perf/fps/tulip2.wav": {"reva": 34239, "revb": 1298213, "type": "absolute", "better": "higher", "improve": 0, "regress": 0}, -"win-release/media_tests_av_perf/dropped_fps/tulip2.wav": {"reva": 181131, "revb": 181572, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "646c02f2"}, -"win-release/media_tests_av_perf/dropped_fps/tulip2.webm": {"reva": 181131, "revb": 181572, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "46c97b57"}, -"win-release/media_tests_av_perf/dropped_frames/crowd1080.webm": {"reva": 181131, "revb": 181572, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "9b709aab"}, -"win-release/media_tests_av_perf/dropped_frames/crowd2160.webm": {"reva": 181131, "revb": 181572, "type": "absolute", "better": "lower", "improve": 174, "regress": 204, "sha1": "4c0270a6"}, -"win-release/media_tests_av_perf/fps/crowd1080.webm": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 53, "regress": 43, "sha1": "7ad49461"}, -"win-release/media_tests_av_perf/fps/crowd2160.webm": {"reva": 176330, "revb": 176978, "type": "absolute", "better": "higher", "improve": 26.0399945997, "regress": 25.9062437562, "sha1": "700526a9"}, -"win-release/media_tests_av_perf/fps/crowd360.webm": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 51, "regress": 47, "sha1": "7f8ef21c"}, -"win-release/media_tests_av_perf/fps/crowd480.webm": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 50, "regress": 47, "sha1": "5dc96881"}, -"win-release/media_tests_av_perf/fps/crowd720.webm": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 52, "regress": 47, "sha1": "4fcfb653"}, -"win-release/media_tests_av_perf/fps/tulip2.m4a": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 0, "regress": 0, "sha1": "54d94538"}, -"win-release/media_tests_av_perf/fps/tulip2.mp3": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 0, "regress": 0, "sha1": "113aef17"}, -"win-release/media_tests_av_perf/fps/tulip2.mp4": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 30, "regress": 28, "sha1": "a22847d0"}, -"win-release/media_tests_av_perf/fps/tulip2.ogg": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 0, "regress": 0, "sha1": "6ee2e716"}, -"win-release/media_tests_av_perf/fps/tulip2.ogv": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 32, "regress": 26, "sha1": "dfadb872"}, -"win-release/media_tests_av_perf/fps/tulip2.wav": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 0, "regress": 0, "sha1": "530c5bf5"}, -"win-release/media_tests_av_perf/fps/tulip2.webm": {"reva": 163299, "revb": 164141, "type": "absolute", "better": "higher", "improve": 30, "regress": 28, "sha1": "35b91c8e"} -} \ No newline at end of file
diff --git a/tools/perf_expectations/tests/perf_expectations_unittest.py b/tools/perf_expectations/tests/perf_expectations_unittest.py deleted file mode 100755 index 9b9b126..0000000 --- a/tools/perf_expectations/tests/perf_expectations_unittest.py +++ /dev/null
@@ -1,167 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Verify perf_expectations.json can be loaded using simplejson. - -perf_expectations.json is a JSON-formatted file. This script verifies -that simplejson can load it correctly. It should catch most common -formatting problems. -""" - -import subprocess -import sys -import os -import unittest -import re - -simplejson = None - -def OnTestsLoad(): - old_path = sys.path - script_path = os.path.dirname(sys.argv[0]) - load_path = None - global simplejson - - # This test script should be stored in src/tools/perf_expectations/. That - # directory will most commonly live in 2 locations: - # - # - a regular Chromium checkout, in which case src/third_party - # is where to look for simplejson - # - # - a buildbot checkout, in which case .../pylibs is where - # to look for simplejson - # - # Locate and install the correct path based on what we can find. - # - for path in ('../../../third_party', '../../../../../pylibs'): - path = os.path.join(script_path, path) - if os.path.exists(path) and os.path.isdir(path): - load_path = os.path.abspath(path) - break - - if load_path is None: - msg = "%s expects to live within a Chromium checkout" % sys.argv[0] - raise Exception, "Error locating simplejson load path (%s)" % msg - - # Try importing simplejson once. If this succeeds, we found it and will - # load it again later properly. Fail if we cannot load it. - sys.path.append(load_path) - try: - import simplejson as Simplejson - simplejson = Simplejson - except ImportError, e: - msg = "%s expects to live within a Chromium checkout" % sys.argv[0] - raise Exception, "Error trying to import simplejson from %s (%s)" % \ - (load_path, msg) - finally: - sys.path = old_path - return True - -def LoadJsonFile(filename): - f = open(filename, 'r') - try: - data = simplejson.load(f) - except ValueError, e: - f.seek(0) - print "Error reading %s:\n%s" % (filename, - f.read()[:50]+'...') - raise e - f.close() - return data - -OnTestsLoad() - -CONFIG_JSON = os.path.join(os.path.dirname(sys.argv[0]), - '../chromium_perf_expectations.cfg') -MAKE_EXPECTATIONS = os.path.join(os.path.dirname(sys.argv[0]), - '../make_expectations.py') -PERF_EXPECTATIONS = os.path.join(os.path.dirname(sys.argv[0]), - '../perf_expectations.json') - - -class PerfExpectationsUnittest(unittest.TestCase): - def testPerfExpectations(self): - # Test data is dictionary. - perf_data = LoadJsonFile(PERF_EXPECTATIONS) - if not isinstance(perf_data, dict): - raise Exception('perf expectations is not a dict') - - # Test the 'load' key. - if not 'load' in perf_data: - raise Exception("perf expectations is missing a load key") - if not isinstance(perf_data['load'], bool): - raise Exception("perf expectations load key has non-bool value") - - # Test all key values are dictionaries. - bad_keys = [] - for key in perf_data: - if key == 'load': - continue - if not isinstance(perf_data[key], dict): - bad_keys.append(key) - if len(bad_keys) > 0: - msg = "perf expectations keys have non-dict values" - raise Exception("%s: %s" % (msg, bad_keys)) - - # Test all key values have delta and var keys. - for key in perf_data: - if key == 'load': - continue - - # First check if regress/improve is in the key's data. - if 'regress' in perf_data[key]: - if 'improve' not in perf_data[key]: - bad_keys.append(key) - if (not isinstance(perf_data[key]['regress'], int) and - not isinstance(perf_data[key]['regress'], float)): - bad_keys.append(key) - if (not isinstance(perf_data[key]['improve'], int) and - not isinstance(perf_data[key]['improve'], float)): - bad_keys.append(key) - else: - # Otherwise check if delta/var is in the key's data. - if 'delta' not in perf_data[key] or 'var' not in perf_data[key]: - bad_keys.append(key) - if (not isinstance(perf_data[key]['delta'], int) and - not isinstance(perf_data[key]['delta'], float)): - bad_keys.append(key) - if (not isinstance(perf_data[key]['var'], int) and - not isinstance(perf_data[key]['var'], float)): - bad_keys.append(key) - - if len(bad_keys) > 0: - msg = "perf expectations key values missing or invalid delta/var" - raise Exception("%s: %s" % (msg, bad_keys)) - - # Test all keys have the correct format. - for key in perf_data: - if key == 'load': - continue - # tools/buildbot/scripts/master/log_parser.py should have a matching - # regular expression. - if not re.match(r"^([\w\.-]+)/([\w\.-]+)/([\w\.-]+)/([\w\.-]+)$", key): - bad_keys.append(key) - if len(bad_keys) > 0: - msg = "perf expectations keys in bad format, expected a/b/c/d" - raise Exception("%s: %s" % (msg, bad_keys)) - - def testNoUpdatesNeeded(self): - p = subprocess.Popen([MAKE_EXPECTATIONS, '-s'], stdout=subprocess.PIPE) - p.wait(); - self.assertEqual(p.returncode, 0, - msg='Update expectations first by running ./make_expectations.py') - - def testConfigFile(self): - # Test that the config file can be parsed as JSON. - config = LoadJsonFile(CONFIG_JSON) - # Require the following keys. - if 'base_url' not in config: - raise Exception('base_url not specified in config file') - if 'perf_file' not in config: - raise Exception('perf_file not specified in config file') - - -if __name__ == '__main__': - unittest.main()
diff --git a/tools/perf_expectations/update_perf_expectations.py b/tools/perf_expectations/update_perf_expectations.py deleted file mode 100755 index d1ce983..0000000 --- a/tools/perf_expectations/update_perf_expectations.py +++ /dev/null
@@ -1,263 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 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. - -"""Prepare tests that require re-baselining for input to make_expectations.py. - -The regularly running perf-AV tests require re-baselineing of expectations -about once a week. The steps involved in rebaselining are: - -1.) Identify the tests to update, based off reported e-mail results. -2.) Figure out reva and revb values, which is the starting and ending revision - numbers for the range that we should use to obtain new thresholds. -3.) Modify lines in perf_expectations.json referring to the tests to be updated, - so that they may be used as input to make_expectations.py. - -This script automates the last step above. - -Here's a sample line from perf_expectations.json: - -"win-release/media_tests_av_perf/fps/tulip2.m4a": {"reva": 163299, \ -"revb": 164141, "type": "absolute", "better": "higher", "improve": 0, \ -"regress": 0, "sha1": "54d94538"}, - -To get the above test ready for input to make_expectations.py, it should become: - -"win-release/media_tests_av_perf/fps/tulip2.m4a": {"reva": <new reva>, \ -"revb": <new revb>, "type": "absolute", "better": "higher", "improve": 0, \ -"regress": 0}, - -Examples: - -1.) To update the test specified above and get baseline -values using the revision range 12345 and 23456, run this script with a command -line like this: - python update_perf_expectations.py -f \ - win-release/media_tests_av_perf/fps/tulip2.m4a --reva 12345 --revb 23456 -Or, using an input file, -where the input file contains a single line with text - win-release/media_tests_av_perf/fps/tulip2.m4a -run with this command line: - python update_perf_expectations.py -i input.txt --reva 12345 --revb 23456 - -2.) Let's say you want to update all seek tests on windows, and get baseline -values using the revision range 12345 and 23456. -Run this script with this command line: - python update_perf_expectations.py -f win-release/media_tests_av_perf/seek/ \ - --reva 12345 --revb 23456 -Or: - python update_perf_expectations.py -f win-release/.*/seek/ --reva 12345 \ - --revb 23456 - -Or, using an input file, -where the input file contains a single line with text win-release/.*/seek/: - python update_perf_expectations.py -i input.txt --reva 12345 --revb 23456 - -3.) Similarly, if you want to update seek tests on all platforms - python update_perf_expectations.py -f .*-release/.*/seek/ --reva 12345 \ - --revb 23456 - -""" - -import logging -from optparse import OptionParser -import os -import re - -import make_expectations as perf_ex_lib - -# Default logging is INFO. Use --verbose to enable DEBUG logging. -_DEFAULT_LOG_LEVEL = logging.INFO - - -def GetTestsToUpdate(contents, all_test_keys): - """Parses input contents and obtains tests to be re-baselined. - - Args: - contents: string containing contents of input file. - all_test_keys: list of keys of test dictionary. - Returns: - A list of keys for tests that should be updated. - """ - # Each line of the input file specifies a test case to update. - tests_list = [] - for test_case_filter in contents.splitlines(): - # Skip any empty lines. - if test_case_filter: - # Sample expected line: - # win-release/media_tests_av_perf/seek/\ - # CACHED_BUFFERED_SEEK_NoConstraints_crowd1080.ogv - # Or, if reg-ex, then sample line: - # win-release/media-tests_av_perf/seek* - # Skip any leading spaces if they exist in the input file. - logging.debug('Trying to match %s', test_case_filter) - tests_list.extend(GetMatchingTests(test_case_filter.strip(), - all_test_keys)) - return tests_list - - -def GetMatchingTests(tests_to_update, all_test_keys): - """Parses input reg-ex filter and obtains tests to be re-baselined. - - Args: - tests_to_update: reg-ex string specifying tests to be updated. - all_test_keys: list of keys of tests dictionary. - Returns: - A list of keys for tests that should be updated. - """ - tests_list = [] - search_string = re.compile(tests_to_update) - # Get matching tests from the dictionary of tests - for test_key in all_test_keys: - if search_string.match(test_key): - tests_list.append(test_key) - logging.debug('%s will be updated', test_key) - logging.info('%s tests found matching reg-ex: %s', len(tests_list), - tests_to_update) - return tests_list - - -def PrepareTestsForUpdate(tests_to_update, all_tests, reva, revb): - """Modifies value of tests that are to re-baselined: - Set reva and revb values to specified new values. Remove sha1. - - Args: - tests_to_update: list of tests to be updated. - all_tests: dictionary of all tests. - reva: oldest revision in range to use for new values. - revb: newest revision in range to use for new values. - Raises: - ValueError: If reva or revb are not valid ints, or if either - of them are negative. - """ - reva = int(reva) - revb = int(revb) - - if reva < 0 or revb < 0: - raise ValueError('Revision values should be positive.') - # Ensure reva is less than revb. - # (this is similar to the check done in make_expectations.py) - if revb < reva: - temp = revb - revb = reva - reva = temp - for test_key in tests_to_update: - # Get original test from the dictionary of tests - test_value = all_tests[test_key] - if test_value: - # Sample line in perf_expectations.json: - # "linux-release/media_tests _av_perf/dropped_frames/crowd360.webm":\ - # {"reva": 155180, "revb": 155280, "type": "absolute", \ - # "better": "lower", "improve": 0, "regress": 3, "sha1": "276ba29c"}, - # Set new revision range - test_value['reva'] = reva - test_value['revb'] = revb - # Remove sha1 to indicate this test requires an update - # Check first to make sure it exist. - if 'sha1' in test_value: - del test_value['sha1'] - else: - logging.warning('%s does not exist.', test_key) - logging.info('Done preparing tests for update.') - - -def GetCommandLineOptions(): - """Parse command line arguments. - - Returns: - An options object containing command line arguments and their values. - """ - parser = OptionParser() - - parser.add_option('--reva', dest='reva', type='int', - help='Starting revision of new range.', - metavar='START_REVISION') - parser.add_option('--revb', dest='revb', type='int', - help='Ending revision of new range.', - metavar='END_REVISION') - parser.add_option('-f', dest='tests_filter', - help='Regex to use for filtering tests to be updated. ' - 'At least one of -filter or -input_file must be provided. ' - 'If both are provided, then input-file is used.', - metavar='FILTER', default='') - parser.add_option('-i', dest='input_file', - help='Optional path to file with reg-exes for tests to' - ' update. If provided, it overrides the filter argument.', - metavar='INPUT_FILE', default='') - parser.add_option('--config', dest='config_file', - default=perf_ex_lib.DEFAULT_CONFIG_FILE, - help='Set the config file to FILE.', metavar='FILE') - parser.add_option('-v', dest='verbose', action='store_true', default=False, - help='Enable verbose output.') - options = parser.parse_args()[0] - return options - - -def Main(): - """Main driver function.""" - options = GetCommandLineOptions() - - _SetLogger(options.verbose) - # Do some command-line validation - if not options.input_file and not options.tests_filter: - logging.error('At least one of input-file or test-filter must be provided.') - exit(1) - if options.input_file and options.tests_filter: - logging.error('Specify only one of input file or test-filter.') - exit(1) - if not options.reva or not options.revb: - logging.error('Start and end revision of range must be specified.') - exit(1) - - # Load config. - config = perf_ex_lib.ConvertJsonIntoDict( - perf_ex_lib.ReadFile(options.config_file)) - - # Obtain the perf expectations file from the config file. - perf_file = os.path.join( - os.path.dirname(options.config_file), config['perf_file']) - - # We should have all the information we require now. - # On to the real thang. - # First, get all the existing tests from the original perf_expectations file. - all_tests = perf_ex_lib.ConvertJsonIntoDict( - perf_ex_lib.ReadFile(perf_file)) - all_test_keys = all_tests.keys() - # Remove the load key, because we don't want to modify it. - all_test_keys.remove('load') - # Keep tests sorted, like in the original file. - all_test_keys.sort() - - # Next, get all tests that have been identified for an update. - tests_to_update = [] - if options.input_file: - # Tests to update have been specified in an input_file. - # Get contents of file. - tests_filter = perf_ex_lib.ReadFile(options.input_file) - elif options.tests_filter: - # Tests to update have been specified as a reg-ex filter. - tests_filter = options.tests_filter - - # Get tests to update based on filter specified. - tests_to_update = GetTestsToUpdate(tests_filter, all_test_keys) - logging.info('Done obtaining matching tests.') - - # Now, prepare tests for update. - PrepareTestsForUpdate(tests_to_update, all_tests, options.reva, options.revb) - - # Finally, write modified tests back to perf_expectations file. - perf_ex_lib.WriteJson(perf_file, all_tests, all_test_keys, - calculate_sha1=False) - logging.info('Done writing tests for update to %s.', perf_file) - - -def _SetLogger(verbose): - log_level = _DEFAULT_LOG_LEVEL - if verbose: - log_level = logging.DEBUG - logging.basicConfig(level=log_level, format='%(message)s') - - -if __name__ == '__main__': - Main()
diff --git a/tools/perf_expectations/update_perf_expectations_unittest.py b/tools/perf_expectations/update_perf_expectations_unittest.py deleted file mode 100755 index 9e54b89..0000000 --- a/tools/perf_expectations/update_perf_expectations_unittest.py +++ /dev/null
@@ -1,204 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 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. -"""Unit tests for update_perf_expectations.""" -import copy -from StringIO import StringIO -import unittest -import make_expectations as perf_ex_lib -import update_perf_expectations as upe_mod - - -# A separate .json file contains the list of test cases we'll use. -# The tests used to be defined inline here, but are >80 characters in length. -# Now they are expected to be defined in file ./sample_test_cases.json. -# Create a dictionary of tests using .json file. -all_tests = perf_ex_lib.ConvertJsonIntoDict( - perf_ex_lib.ReadFile('sample_test_cases.json')) -# Get all keys. -all_tests_keys = all_tests.keys() - - -def VerifyPreparedTests(self, tests_to_update, reva, revb): - # Work with a copy of the set of tests. - all_tests_copy = copy.deepcopy(all_tests) - upe_mod.PrepareTestsForUpdate(tests_to_update, all_tests_copy, reva, revb) - # Make sure reva < revb - if reva > revb: - temp = reva - reva = revb - revb = temp - # Run through all tests and make sure only those that were - # specified to be modified had their 'sha1' value removed. - for test_key in all_tests_keys: - new_test_value = all_tests_copy[test_key] - original_test_value = all_tests[test_key] - if test_key in tests_to_update: - # Make sure there is no "sha1". - self.assertFalse('sha1' in new_test_value) - # Make sure reva and revb values are correctly set. - self.assertEqual(reva, new_test_value['reva']) - self.assertEqual(revb, new_test_value['revb']) - else: - # Make sure there is an "sha1" value - self.assertTrue('sha1' in new_test_value) - # Make sure the sha1, reva and revb values have not changed. - self.assertEqual(original_test_value['sha1'], new_test_value['sha1']) - self.assertEqual(original_test_value['reva'], new_test_value['reva']) - self.assertEqual(original_test_value['revb'], new_test_value['revb']) - - -class UpdatePerfExpectationsTest(unittest.TestCase): - def testFilterMatch(self): - """Verifies different regular expressions test filter.""" - self.maxDiff = None - # Tests to update specified by a single literal string. - tests_to_update = 'win-release/media_tests_av_perf/fps/tulip2.webm' - expected_tests_list = ['win-release/media_tests_av_perf/fps/tulip2.webm'] - self.assertEqual(expected_tests_list, - upe_mod.GetMatchingTests(tests_to_update, - all_tests_keys)) - - # Tests to update specified by a single reg-ex - tests_to_update = 'win-release/media_tests_av_perf/fps.*' - expected_tests_list = ['win-release/media_tests_av_perf/fps/crowd1080.webm', - 'win-release/media_tests_av_perf/fps/crowd2160.webm', - 'win-release/media_tests_av_perf/fps/crowd360.webm', - 'win-release/media_tests_av_perf/fps/crowd480.webm', - 'win-release/media_tests_av_perf/fps/crowd720.webm', - 'win-release/media_tests_av_perf/fps/tulip2.m4a', - 'win-release/media_tests_av_perf/fps/tulip2.mp3', - 'win-release/media_tests_av_perf/fps/tulip2.mp4', - 'win-release/media_tests_av_perf/fps/tulip2.ogg', - 'win-release/media_tests_av_perf/fps/tulip2.ogv', - 'win-release/media_tests_av_perf/fps/tulip2.wav', - 'win-release/media_tests_av_perf/fps/tulip2.webm'] - actual_list = upe_mod.GetMatchingTests(tests_to_update, - all_tests_keys) - actual_list.sort() - self.assertEqual(expected_tests_list, actual_list) - - # Tests to update are specified by a single reg-ex, spanning multiple OSes. - tests_to_update = '.*-release/media_tests_av_perf/fps.*' - expected_tests_list = ['linux-release/media_tests_av_perf/fps/tulip2.m4a', - 'linux-release/media_tests_av_perf/fps/tulip2.mp3', - 'linux-release/media_tests_av_perf/fps/tulip2.mp4', - 'linux-release/media_tests_av_perf/fps/tulip2.ogg', - 'linux-release/media_tests_av_perf/fps/tulip2.ogv', - 'linux-release/media_tests_av_perf/fps/tulip2.wav', - 'win-release/media_tests_av_perf/fps/crowd1080.webm', - 'win-release/media_tests_av_perf/fps/crowd2160.webm', - 'win-release/media_tests_av_perf/fps/crowd360.webm', - 'win-release/media_tests_av_perf/fps/crowd480.webm', - 'win-release/media_tests_av_perf/fps/crowd720.webm', - 'win-release/media_tests_av_perf/fps/tulip2.m4a', - 'win-release/media_tests_av_perf/fps/tulip2.mp3', - 'win-release/media_tests_av_perf/fps/tulip2.mp4', - 'win-release/media_tests_av_perf/fps/tulip2.ogg', - 'win-release/media_tests_av_perf/fps/tulip2.ogv', - 'win-release/media_tests_av_perf/fps/tulip2.wav', - 'win-release/media_tests_av_perf/fps/tulip2.webm'] - actual_list = upe_mod.GetMatchingTests(tests_to_update, - all_tests_keys) - actual_list.sort() - self.assertEqual(expected_tests_list, actual_list) - - def testLinesFromInputFile(self): - """Verifies different string formats specified in input file.""" - - # Tests to update have been specified by a single literal string in - # an input file. - # Use the StringIO class to mock a file object. - lines_from_file = StringIO( - 'win-release/media_tests_av_perf/fps/tulip2.webm') - contents = lines_from_file.read() - expected_tests_list = ['win-release/media_tests_av_perf/fps/tulip2.webm'] - actual_list = upe_mod.GetTestsToUpdate(contents, all_tests_keys) - actual_list.sort() - self.assertEqual(expected_tests_list, actual_list) - lines_from_file.close() - - # Tests to update specified by a single reg-ex in an input file. - lines_from_file = StringIO('win-release/media_tests_av_perf/fps/tulip2.*\n') - contents = lines_from_file.read() - expected_tests_list = ['win-release/media_tests_av_perf/fps/tulip2.m4a', - 'win-release/media_tests_av_perf/fps/tulip2.mp3', - 'win-release/media_tests_av_perf/fps/tulip2.mp4', - 'win-release/media_tests_av_perf/fps/tulip2.ogg', - 'win-release/media_tests_av_perf/fps/tulip2.ogv', - 'win-release/media_tests_av_perf/fps/tulip2.wav', - 'win-release/media_tests_av_perf/fps/tulip2.webm'] - actual_list = upe_mod.GetTestsToUpdate(contents, all_tests_keys) - actual_list.sort() - self.assertEqual(expected_tests_list, actual_list) - lines_from_file.close() - - # Tests to update specified by multiple lines in an input file. - lines_from_file = StringIO( - '.*-release/media_tests_av_perf/fps/tulip2.*\n' - 'win-release/media_tests_av_perf/dropped_fps/tulip2.*\n' - 'linux-release/media_tests_av_perf/audio_latency/latency') - contents = lines_from_file.read() - expected_tests_list = [ - 'linux-release/media_tests_av_perf/audio_latency/latency', - 'linux-release/media_tests_av_perf/fps/tulip2.m4a', - 'linux-release/media_tests_av_perf/fps/tulip2.mp3', - 'linux-release/media_tests_av_perf/fps/tulip2.mp4', - 'linux-release/media_tests_av_perf/fps/tulip2.ogg', - 'linux-release/media_tests_av_perf/fps/tulip2.ogv', - 'linux-release/media_tests_av_perf/fps/tulip2.wav', - 'win-release/media_tests_av_perf/dropped_fps/tulip2.wav', - 'win-release/media_tests_av_perf/dropped_fps/tulip2.webm', - 'win-release/media_tests_av_perf/fps/tulip2.m4a', - 'win-release/media_tests_av_perf/fps/tulip2.mp3', - 'win-release/media_tests_av_perf/fps/tulip2.mp4', - 'win-release/media_tests_av_perf/fps/tulip2.ogg', - 'win-release/media_tests_av_perf/fps/tulip2.ogv', - 'win-release/media_tests_av_perf/fps/tulip2.wav', - 'win-release/media_tests_av_perf/fps/tulip2.webm'] - actual_list = upe_mod.GetTestsToUpdate(contents, all_tests_keys) - actual_list.sort() - self.assertEqual(expected_tests_list, actual_list) - lines_from_file.close() - - def testPreparingForUpdate(self): - """Verifies that tests to be modified are changed as expected.""" - tests_to_update = [ - 'linux-release/media_tests_av_perf/audio_latency/latency', - 'linux-release/media_tests_av_perf/fps/tulip2.m4a', - 'linux-release/media_tests_av_perf/fps/tulip2.mp3', - 'linux-release/media_tests_av_perf/fps/tulip2.mp4', - 'linux-release/media_tests_av_perf/fps/tulip2.ogg', - 'linux-release/media_tests_av_perf/fps/tulip2.ogv', - 'linux-release/media_tests_av_perf/fps/tulip2.wav', - 'win-release/media_tests_av_perf/dropped_fps/tulip2.wav', - 'win-release/media_tests_av_perf/dropped_fps/tulip2.webm', - 'win-release/media_tests_av_perf/fps/tulip2.mp3', - 'win-release/media_tests_av_perf/fps/tulip2.mp4', - 'win-release/media_tests_av_perf/fps/tulip2.ogg', - 'win-release/media_tests_av_perf/fps/tulip2.ogv', - 'win-release/media_tests_av_perf/fps/tulip2.wav', - 'win-release/media_tests_av_perf/fps/tulip2.webm'] - # Test regular positive integers. - reva = 12345 - revb = 54321 - VerifyPreparedTests(self, tests_to_update, reva, revb) - # Test negative values. - reva = -54321 - revb = 12345 - with self.assertRaises(ValueError): - upe_mod.PrepareTestsForUpdate(tests_to_update, all_tests, reva, revb) - # Test reva greater than revb. - reva = 54321 - revb = 12345 - upe_mod.PrepareTestsForUpdate(tests_to_update, all_tests, reva, revb) - # Test non-integer values - reva = 'sds' - revb = 12345 - with self.assertRaises(ValueError): - upe_mod.PrepareTestsForUpdate(tests_to_update, all_tests, reva, revb) - - -if __name__ == '__main__': - unittest.main()
diff --git a/ui/accessibility/ax_role_properties.cc b/ui/accessibility/ax_role_properties.cc index 0ea7ac9..487ba26d 100644 --- a/ui/accessibility/ax_role_properties.cc +++ b/ui/accessibility/ax_role_properties.cc
@@ -8,7 +8,7 @@ namespace ui { namespace { -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_CHROMEOS) static bool kExposeLayoutTableAsDataTable = true; #else static bool kExposeLayoutTableAsDataTable = false; @@ -120,6 +120,27 @@ } } +bool IsTableHeaderRole(ax::mojom::Role role) { + switch (role) { + case ax::mojom::Role::kColumnHeader: + case ax::mojom::Role::kRowHeader: + return true; + default: + return false; + } +} + +bool IsTableRowRole(ax::mojom::Role role) { + switch (role) { + case ax::mojom::Role::kRow: + return true; + case ax::mojom::Role::kLayoutTableRow: + return kExposeLayoutTableAsDataTable; + default: + return false; + } +} + bool IsContainerWithSelectableChildrenRole(ax::mojom::Role role) { switch (role) { case ax::mojom::Role::kComboBoxGrouping:
diff --git a/ui/accessibility/ax_role_properties.h b/ui/accessibility/ax_role_properties.h index a99c785..bfb756f9 100644 --- a/ui/accessibility/ax_role_properties.h +++ b/ui/accessibility/ax_role_properties.h
@@ -32,6 +32,12 @@ // Returns true if this node is a table, a grid or a treegrid. AX_EXPORT bool IsTableLikeRole(ax::mojom::Role role); +// Returns true if this node is a table header. +AX_EXPORT bool IsTableHeaderRole(ax::mojom::Role role); + +// Returns true if this node is a row. +AX_EXPORT bool IsTableRowRole(ax::mojom::Role role); + // Returns true if the provided role is selectable from the standpoint of UI // automation. AX_EXPORT bool IsUIASelectable(ax::mojom::Role role);
diff --git a/ui/base/accelerators/accelerator.h b/ui/base/accelerators/accelerator.h index 1ea2afec..f5304b8e 100644 --- a/ui/base/accelerators/accelerator.h +++ b/ui/base/accelerators/accelerator.h
@@ -38,6 +38,11 @@ }; Accelerator(); + // |modifiers| consists of ui::EventFlags bitwise-or-ed together, + // for example: + // Accelerator(ui::VKEY_Z, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN) + // would correspond to the shortcut "ctrl + shift + z". + // // NOTE: this constructor strips out non key related flags. Accelerator(KeyboardCode key_code, int modifiers,
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 92ed2ff0..b3905bd 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -389,11 +389,8 @@ void BeginMainFrameNotExpectedSoon() override; void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override; void UpdateLayerTreeHost() override; - void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float page_scale, - float top_controls_delta) override {} + void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override { + } void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel, bool has_scrolled_by_touch) override {} void RequestNewLayerTreeFrameSink() override;
diff --git a/ui/display/BUILD.gn b/ui/display/BUILD.gn index 1fba4a9..4d1e88b6 100644 --- a/ui/display/BUILD.gn +++ b/ui/display/BUILD.gn
@@ -56,6 +56,7 @@ public_deps = [ "//ui/display/types", + "//ui/gfx:color_space", "//ui/gfx:gfx", ]
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn index 5626512..75bd864 100644 --- a/ui/events/BUILD.gn +++ b/ui/events/BUILD.gn
@@ -218,6 +218,7 @@ public_deps = [ ":events_base", + "//ui/display", "//ui/latency", ] deps = [ @@ -225,7 +226,6 @@ ":gesture_detection", "//base/third_party/dynamic_annotations", "//skia", - "//ui/display", "//ui/gfx", "//ui/gfx/geometry", ] @@ -532,8 +532,8 @@ "//ui/events/devices", "//ui/events/devices/mojo:test_interfaces", "//ui/events/gestures/blink", - "//ui/events/mojo:test_interfaces", "//ui/events/platform", + "//ui/gfx/geometry/mojo:struct_traits", "//ui/gfx/ipc/geometry", ]
diff --git a/ui/events/event.h b/ui/events/event.h index 5bbc071..b9b4c72 100644 --- a/ui/events/event.h +++ b/ui/events/event.h
@@ -34,6 +34,7 @@ namespace ui { class CancelModeEvent; +class Event; class EventTarget; class KeyEvent; class LocatedEvent; @@ -42,11 +43,9 @@ class PointerEvent; class ScrollEvent; class TouchEvent; -enum class DomCode; -class Event; -class MouseWheelEvent; -using ScopedEvent = std::unique_ptr<Event>; +enum class DomCode; + using PointerId = int32_t; class EVENTS_EXPORT Event {
diff --git a/ui/events/mojo/BUILD.gn b/ui/events/mojo/BUILD.gn index 9515ba4..a4523c5 100644 --- a/ui/events/mojo/BUILD.gn +++ b/ui/events/mojo/BUILD.gn
@@ -13,18 +13,7 @@ public_deps = [ "//mojo/public/mojom/base", - "//ui/gfx/mojo", + "//ui/gfx/geometry/mojo", "//ui/latency/mojo:interfaces", ] } - -mojom("test_interfaces") { - testonly = true - sources = [ - "traits_test_service.mojom", - ] - - public_deps = [ - ":interfaces", - ] -}
diff --git a/ui/events/mojo/event.mojom b/ui/events/mojo/event.mojom index 739f984..9dafcc2 100644 --- a/ui/events/mojo/event.mojom +++ b/ui/events/mojo/event.mojom
@@ -7,6 +7,7 @@ import "mojo/public/mojom/base/time.mojom"; import "ui/events/mojo/event_constants.mojom"; import "ui/events/mojo/keyboard_codes.mojom"; +import "ui/gfx/geometry/mojo/geometry.mojom"; import "ui/latency/mojo/latency_info.mojom"; struct KeyData { @@ -49,17 +50,10 @@ }; struct LocationData { - // |x| and |y| are in the coordinate system of the View. - // Typically, this will be an integer-valued translation w.r.t. - // the screen and in this case, |x| and |y| are in units of physical - // pixels. However, some View embedders may apply arbitrary transformations - // of a view w.r.t. the screen. - float x; - float y; - // |screen_x| and |screen_y| are in screen coordinates in units of - // physical pixels. - float screen_x; - float screen_y; + // |relative_location| is in the coordinate system of the target and in DIPs. + gfx.mojom.PointF relative_location; + // |root_location| is relative to the client's root and in dips. + gfx.mojom.PointF root_location; }; // TODO(rjkroege,sadrul): Add gesture representation. @@ -155,6 +149,14 @@ int32 offset_y; }; +struct MouseData { + int32 changed_button_flags; + LocationData location; + PointerDetails pointer_details; + // Only used for mouse wheel. + gfx.mojom.Vector2d wheel_offset; +}; + // This is used for TouchEvents. struct TouchData { bool may_cause_scrolling; @@ -181,5 +183,6 @@ GestureData? gesture_data; ScrollData? scroll_data; TouchData? touch_data; + MouseData? mouse_data; map<string, array<uint8>>? properties; };
diff --git a/ui/events/mojo/event.typemap b/ui/events/mojo/event.typemap index 2adfd2b2..a652049b 100644 --- a/ui/events/mojo/event.typemap +++ b/ui/events/mojo/event.typemap
@@ -8,6 +8,7 @@ public_deps = [ "//ui/events", "//ui/events:dom_keycode_converter", + "//ui/gfx/geometry/mojo", "//ui/latency/mojo:interfaces", ] deps = [
diff --git a/ui/events/mojo/event_struct_traits.cc b/ui/events/mojo/event_struct_traits.cc index b7ee9a2..c5324bb 100644 --- a/ui/events/mojo/event_struct_traits.cc +++ b/ui/events/mojo/event_struct_traits.cc
@@ -17,28 +17,22 @@ namespace { -ui::mojom::LocationDataPtr GetLocationData(const ui::LocatedEvent* event) { +ui::mojom::LocationDataPtr CreateLocationData(const ui::LocatedEvent* event) { ui::mojom::LocationDataPtr location_data(ui::mojom::LocationData::New()); - location_data->x = event->location_f().x(); - location_data->y = event->location_f().y(); - location_data->screen_x = event->root_location_f().x(); - location_data->screen_y = event->root_location_f().y(); + location_data->relative_location = event->location_f(); + location_data->root_location = event->root_location_f(); return location_data; } void UpdateEventLocation(const ui::mojom::PointerData& pointer_data, EventUniquePtr* out) { - // TODO(katie): Update LocationData to have two PointF instead of storing this - // as four floats. - const gfx::PointF location(pointer_data.location->x, - pointer_data.location->y); - const gfx::PointF screen_location(pointer_data.location->screen_x, - pointer_data.location->screen_y); // Set the float location, as the constructor only takes a gfx::Point. // This uses the event root_location field to store screen pixel // coordinates. See http://crbug.com/608547 - out->get()->AsLocatedEvent()->set_location_f(location); - out->get()->AsLocatedEvent()->set_root_location_f(screen_location); + out->get()->AsLocatedEvent()->set_location_f( + pointer_data.location->relative_location); + out->get()->AsLocatedEvent()->set_root_location_f( + pointer_data.location->root_location); } bool ReadPointerDetailsDeprecated(ui::mojom::EventType event_type, @@ -92,7 +86,8 @@ *out = std::make_unique<ui::ScrollEvent>( mojo::ConvertTo<ui::EventType>(event->action()), - gfx::Point(scroll_data->location->x, scroll_data->location->y), + gfx::Point(scroll_data->location->relative_location.x(), + scroll_data->location->relative_location.y()), time_stamp, event->flags(), scroll_data->x_offset, scroll_data->y_offset, scroll_data->x_offset_ordinal, scroll_data->y_offset_ordinal, scroll_data->finger_count, scroll_data->momentum_phase); @@ -107,8 +102,8 @@ return false; *out = std::make_unique<ui::GestureEvent>( - gesture_data->location->x, gesture_data->location->y, event->flags(), - time_stamp, + gesture_data->location->relative_location.x(), + gesture_data->location->relative_location.y(), event->flags(), time_stamp, ui::GestureEventDetails(ConvertTo<ui::EventType>(event->action()))); return true; } @@ -347,24 +342,14 @@ ui::mojom::PointerDataPtr StructTraits<ui::mojom::EventDataView, EventUniquePtr>::pointer_data( const EventUniquePtr& event) { - if (!event->IsPointerEvent() && !event->IsMouseEvent()) + if (!event->IsPointerEvent()) return nullptr; ui::mojom::PointerDataPtr pointer_data(ui::mojom::PointerData::New()); - const ui::PointerDetails* pointer_details; - if (event->IsPointerEvent()) { - const ui::PointerEvent* pointer_event = event->AsPointerEvent(); - pointer_data->changed_button_flags = pointer_event->changed_button_flags(); - pointer_data->location = GetLocationData(event->AsLocatedEvent()); - pointer_details = &pointer_event->pointer_details(); - } else { - // Mouse event - const ui::MouseEvent* mouse_event = event->AsMouseEvent(); - pointer_data->changed_button_flags = mouse_event->changed_button_flags(); - pointer_data->location = GetLocationData(mouse_event); - pointer_details = &mouse_event->pointer_details(); - } - + const ui::PointerEvent* pointer_event = event->AsPointerEvent(); + const ui::PointerDetails* pointer_details = &pointer_event->pointer_details(); + pointer_data->changed_button_flags = pointer_event->changed_button_flags(); + pointer_data->location = CreateLocationData(event->AsLocatedEvent()); pointer_data->pointer_id = pointer_details->id; ui::EventPointerType pointer_type = pointer_details->pointer_type; @@ -403,8 +388,7 @@ // TODO(rjkroege): Handle force-touch on MacOS // TODO(rjkroege): Adjust brush data appropriately for Android. - if (event->type() == ui::ET_POINTER_WHEEL_CHANGED || - event->type() == ui::ET_MOUSEWHEEL) { + if (event->type() == ui::ET_POINTER_WHEEL_CHANGED) { ui::mojom::WheelDataPtr wheel_data(ui::mojom::WheelData::New()); // TODO(rjkroege): Support page scrolling on windows by directly @@ -430,6 +414,23 @@ } // static +ui::mojom::MouseDataPtr +StructTraits<ui::mojom::EventDataView, EventUniquePtr>::mouse_data( + const EventUniquePtr& event) { + if (!event->IsMouseEvent()) + return nullptr; + + const ui::MouseEvent* mouse_event = event->AsMouseEvent(); + ui::mojom::MouseDataPtr mouse_data(ui::mojom::MouseData::New()); + mouse_data->changed_button_flags = mouse_event->changed_button_flags(); + mouse_data->pointer_details = mouse_event->pointer_details(); + mouse_data->location = CreateLocationData(mouse_event); + if (mouse_event->IsMouseWheelEvent()) + mouse_data->wheel_offset = mouse_event->AsMouseWheelEvent()->offset(); + return mouse_data; +} + +// static ui::mojom::GestureDataPtr StructTraits<ui::mojom::EventDataView, EventUniquePtr>::gesture_data( const EventUniquePtr& event) { @@ -437,7 +438,7 @@ return nullptr; ui::mojom::GestureDataPtr gesture_data(ui::mojom::GestureData::New()); - gesture_data->location = GetLocationData(event->AsLocatedEvent()); + gesture_data->location = CreateLocationData(event->AsLocatedEvent()); return gesture_data; } @@ -449,7 +450,7 @@ return nullptr; ui::mojom::ScrollDataPtr scroll_data(ui::mojom::ScrollData::New()); - scroll_data->location = GetLocationData(event->AsLocatedEvent()); + scroll_data->location = CreateLocationData(event->AsLocatedEvent()); const ui::ScrollEvent* scroll_event = event->AsScrollEvent(); scroll_data->x_offset = scroll_event->x_offset(); scroll_data->y_offset = scroll_event->y_offset(); @@ -471,11 +472,7 @@ ui::mojom::TouchDataPtr touch_data(ui::mojom::TouchData::New()); touch_data->may_cause_scrolling = touch_event->may_cause_scrolling(); touch_data->hovering = touch_event->hovering(); - touch_data->location = ui::mojom::LocationData::New(); - touch_data->location->x = touch_event->location_f().x(); - touch_data->location->y = touch_event->location_f().y(); - touch_data->location->screen_x = touch_event->root_location_f().x(); - touch_data->location->screen_y = touch_event->root_location_f().y(); + touch_data->location = CreateLocationData(touch_event); touch_data->pointer_details = touch_event->pointer_details(); return touch_data; } @@ -574,33 +571,28 @@ case ui::mojom::EventType::MOUSE_EXITED_EVENT: case ui::mojom::EventType::MOUSE_WHEEL_EVENT: case ui::mojom::EventType::MOUSE_CAPTURE_CHANGED_EVENT: { - ui::mojom::PointerDataPtr pointer_data; - if (!event.ReadPointerData<ui::mojom::PointerDataPtr>(&pointer_data)) + ui::mojom::MouseDataPtr mouse_data; + if (!event.ReadMouseData(&mouse_data)) return false; - ui::PointerDetails pointer_details; - if (!ReadPointerDetailsDeprecated(event.action(), *pointer_data, - &pointer_details)) - return false; - + std::unique_ptr<ui::MouseEvent> mouse_event; if (event.action() == ui::mojom::EventType::MOUSE_WHEEL_EVENT) { - // Use the mouse event to construct a MouseWheel event to avoid asserts - // in ui::MouseEvent's constructor that ensure it is not used to create - // a wheel event. - ui::MouseEvent mouse_event( - ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), time_stamp, - event.flags(), pointer_data->changed_button_flags, pointer_details); - *out = std::make_unique<ui::MouseWheelEvent>( - mouse_event, pointer_details.offset.x(), - pointer_details.offset.y()); + mouse_event = std::make_unique<ui::MouseWheelEvent>( + mouse_data->wheel_offset, + gfx::Point(), // Real location set below. + gfx::Point(), // Real location set below. + time_stamp, event.flags(), mouse_data->changed_button_flags); } else { - *out = std::make_unique<ui::MouseEvent>( - mojo::ConvertTo<ui::EventType>(event.action()), gfx::Point(), - gfx::Point(), time_stamp, event.flags(), - pointer_data->changed_button_flags, pointer_details); + mouse_event = std::make_unique<ui::MouseEvent>( + mojo::ConvertTo<ui::EventType>(event.action()), + gfx::Point(), // Real location set below. + gfx::Point(), // Real location set below. + time_stamp, event.flags(), mouse_data->changed_button_flags, + mouse_data->pointer_details); } - - UpdateEventLocation(*pointer_data, out); + mouse_event->set_location_f(mouse_data->location->relative_location); + mouse_event->set_root_location_f(mouse_data->location->root_location); + *out = std::move(mouse_event); break; } case ui::mojom::EventType::TOUCH_RELEASED: @@ -615,14 +607,12 @@ mojo::ConvertTo<ui::EventType>(event.action()), gfx::Point(), // Real location set below. time_stamp, touch_data->pointer_details, event.flags()); - touch_event->set_location_f( - gfx::PointF(touch_data->location->x, touch_data->location->y)); - touch_event->set_root_location_f(gfx::PointF( - touch_data->location->screen_x, touch_data->location->screen_y)); + touch_event->set_location_f(touch_data->location->relative_location); + touch_event->set_root_location_f(touch_data->location->root_location); touch_event->set_may_cause_scrolling(touch_data->may_cause_scrolling); touch_event->set_hovering(touch_data->hovering); *out = std::move(touch_event); - return true; + break; } case ui::mojom::EventType::UNKNOWN: NOTREACHED() << "Using unknown event types closes connections";
diff --git a/ui/events/mojo/event_struct_traits.h b/ui/events/mojo/event_struct_traits.h index c6b09d2..1e5d3fb1 100644 --- a/ui/events/mojo/event_struct_traits.h +++ b/ui/events/mojo/event_struct_traits.h
@@ -46,6 +46,7 @@ static ui::mojom::GestureDataPtr gesture_data(const EventUniquePtr& event); static ui::mojom::ScrollDataPtr scroll_data(const EventUniquePtr& event); static ui::mojom::TouchDataPtr touch_data(const EventUniquePtr& event); + static ui::mojom::MouseDataPtr mouse_data(const EventUniquePtr& event); static base::flat_map<std::string, std::vector<uint8_t>> properties( const EventUniquePtr& event); static bool Read(ui::mojom::EventDataView r, EventUniquePtr* out);
diff --git a/ui/events/mojo/struct_traits_unittest.cc b/ui/events/mojo/struct_traits_unittest.cc index 7a774c0..2c4d62b 100644 --- a/ui/events/mojo/struct_traits_unittest.cc +++ b/ui/events/mojo/struct_traits_unittest.cc
@@ -4,47 +4,21 @@ #include <utility> -#include "base/message_loop/message_loop.h" #include "base/stl_util.h" #include "mojo/public/cpp/base/time_mojom_traits.h" -#include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/test_support/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/event.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/mojo/event.mojom.h" #include "ui/events/mojo/event_struct_traits.h" -#include "ui/events/mojo/traits_test_service.mojom.h" +#include "ui/gfx/geometry/mojo/geometry_struct_traits.h" #include "ui/latency/mojo/latency_info_struct_traits.h" namespace ui { namespace { -class StructTraitsTest : public testing::Test, public mojom::TraitsTestService { - public: - StructTraitsTest() {} - ~StructTraitsTest() override = default; - - protected: - mojom::TraitsTestServicePtr GetTraitsTestProxy() { - mojom::TraitsTestServicePtr proxy; - traits_test_bindings_.AddBinding(this, mojo::MakeRequest(&proxy)); - return proxy; - } - - private: - // TraitsTestService: - void EchoEvent(std::unique_ptr<ui::Event> e, - EchoEventCallback callback) override { - std::move(callback).Run(std::move(e)); - } - - base::MessageLoop loop_; - mojo::BindingSet<TraitsTestService> traits_test_bindings_; - DISALLOW_COPY_AND_ASSIGN(StructTraitsTest); -}; - void ExpectTouchEventsEqual(const TouchEvent& expected, const TouchEvent& actual) { EXPECT_EQ(expected.may_cause_scrolling(), actual.may_cause_scrolling()); @@ -64,6 +38,11 @@ EXPECT_EQ(expected.changed_button_flags(), actual.changed_button_flags()); } +void ExpectMouseWheelEventsEqual(const MouseWheelEvent& expected, + const MouseWheelEvent& actual) { + EXPECT_EQ(expected.offset(), actual.offset()); +} + void ExpectEventsEqual(const Event& expected, const Event& actual) { EXPECT_EQ(expected.type(), actual.type()); EXPECT_EQ(expected.time_stamp(), actual.time_stamp()); @@ -77,6 +56,11 @@ ASSERT_TRUE(actual.IsMouseEvent()); ExpectMouseEventsEqual(*expected.AsMouseEvent(), *actual.AsMouseEvent()); } + if (expected.IsMouseWheelEvent()) { + ASSERT_TRUE(actual.IsMouseWheelEvent()); + ExpectMouseWheelEventsEqual(*expected.AsMouseWheelEvent(), + *actual.AsMouseWheelEvent()); + } if (expected.IsTouchEvent()) { ASSERT_TRUE(actual.IsTouchEvent()); ExpectTouchEventsEqual(*expected.AsTouchEvent(), *actual.AsTouchEvent()); @@ -85,28 +69,28 @@ } // namespace -TEST_F(StructTraitsTest, KeyEvent) { +TEST(StructTraitsTest, KeyEvent) { const KeyEvent kTestData[] = { {ET_KEY_PRESSED, VKEY_RETURN, EF_CONTROL_DOWN}, {ET_KEY_PRESSED, VKEY_MENU, EF_ALT_DOWN}, {ET_KEY_RELEASED, VKEY_SHIFT, EF_SHIFT_DOWN}, {ET_KEY_RELEASED, VKEY_MENU, EF_ALT_DOWN}, - {ET_KEY_PRESSED, VKEY_A, ui::DomCode::US_A, EF_NONE}, - {ET_KEY_PRESSED, VKEY_B, ui::DomCode::US_B, - EF_CONTROL_DOWN | EF_ALT_DOWN}, - {'\x12', VKEY_2, ui::DomCode::NONE, EF_CONTROL_DOWN}, - {'Z', VKEY_Z, ui::DomCode::NONE, EF_CAPS_LOCK_ON}, - {'z', VKEY_Z, ui::DomCode::NONE, EF_NONE}, + {ET_KEY_PRESSED, VKEY_A, DomCode::US_A, EF_NONE}, + {ET_KEY_PRESSED, VKEY_B, DomCode::US_B, EF_CONTROL_DOWN | EF_ALT_DOWN}, + {'\x12', VKEY_2, DomCode::NONE, EF_CONTROL_DOWN}, + {'Z', VKEY_Z, DomCode::NONE, EF_CAPS_LOCK_ON}, + {'z', VKEY_Z, DomCode::NONE, EF_NONE}, {ET_KEY_PRESSED, VKEY_Z, EF_NONE, base::TimeTicks() + base::TimeDelta::FromMicroseconds(101)}, - {'Z', VKEY_Z, ui::DomCode::NONE, EF_NONE, + {'Z', VKEY_Z, DomCode::NONE, EF_NONE, base::TimeTicks() + base::TimeDelta::FromMicroseconds(102)}, }; - mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); for (size_t i = 0; i < base::size(kTestData); i++) { + std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); std::unique_ptr<Event> output; - proxy->EchoEvent(Event::Clone(kTestData[i]), &output); + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>( + &expected_copy, &output)); EXPECT_TRUE(output->IsKeyEvent()); const KeyEvent* output_key_event = output->AsKeyEvent(); @@ -123,7 +107,7 @@ } } -TEST_F(StructTraitsTest, PointerEvent) { +TEST(StructTraitsTest, PointerEvent) { const PointerEvent kTestData[] = { // Mouse pointer events: {ET_POINTER_DOWN, gfx::Point(10, 10), gfx::Point(20, 30), EF_NONE, 0, @@ -206,10 +190,11 @@ base::TimeTicks() + base::TimeDelta::FromMicroseconds(211)}, }; - mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); for (size_t i = 0; i < base::size(kTestData); i++) { + std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); std::unique_ptr<Event> output; - proxy->EchoEvent(Event::Clone(kTestData[i]), &output); + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>( + &expected_copy, &output)); EXPECT_TRUE(output->IsPointerEvent()); const PointerEvent* output_ptr_event = output->AsPointerEvent(); @@ -227,7 +212,7 @@ } } -TEST_F(StructTraitsTest, MouseEvent) { +TEST(StructTraitsTest, MouseEvent) { const MouseEvent kTestData[] = { {ET_MOUSE_PRESSED, gfx::Point(10, 10), gfx::Point(20, 30), base::TimeTicks() + base::TimeDelta::FromMicroseconds(201), EF_NONE, 0, @@ -264,17 +249,18 @@ MouseEvent::kMousePointerId)}, }; - mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); for (size_t i = 0; i < base::size(kTestData); i++) { + std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); std::unique_ptr<Event> output; - proxy->EchoEvent(Event::Clone(kTestData[i]), &output); + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>( + &expected_copy, &output)); ASSERT_TRUE(output->IsMouseEvent()); ExpectEventsEqual(kTestData[i], *output); } } -TEST_F(StructTraitsTest, PointerWheelEvent) { +TEST(StructTraitsTest, PointerWheelEvent) { const MouseWheelEvent kTestData[] = { {gfx::Vector2d(11, 15), gfx::Point(3, 4), gfx::Point(40, 30), base::TimeTicks() + base::TimeDelta::FromMicroseconds(301), @@ -288,10 +274,12 @@ EF_NONE}, }; - mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); for (size_t i = 0; i < base::size(kTestData); i++) { + std::unique_ptr<Event> expected_copy = + std::make_unique<PointerEvent>(kTestData[i]); std::unique_ptr<Event> output; - proxy->EchoEvent(Event::Clone(ui::PointerEvent(kTestData[i])), &output); + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>( + &expected_copy, &output)); EXPECT_EQ(ET_POINTER_WHEEL_CHANGED, output->type()); const PointerEvent* output_pointer_event = output->AsPointerEvent(); @@ -306,7 +294,7 @@ } } -TEST_F(StructTraitsTest, MouseWheelEvent) { +TEST(StructTraitsTest, MouseWheelEvent) { const MouseWheelEvent kTestData[] = { {gfx::Vector2d(11, 15), gfx::Point(3, 4), gfx::Point(40, 30), base::TimeTicks() + base::TimeDelta::FromMicroseconds(301), @@ -320,44 +308,40 @@ EF_NONE}, }; - mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); for (size_t i = 0; i < base::size(kTestData); i++) { + std::unique_ptr<Event> expected_copy = + std::make_unique<MouseWheelEvent>(PointerEvent(kTestData[i])); std::unique_ptr<Event> output; - proxy->EchoEvent( - Event::Clone(ui::MouseWheelEvent(ui::PointerEvent(kTestData[i]))), - &output); + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>( + &expected_copy, &output)); ASSERT_EQ(ET_MOUSEWHEEL, output->type()); const MouseWheelEvent* output_event = output->AsMouseWheelEvent(); // TODO(sky): make this use ExpectEventsEqual(). - EXPECT_EQ(ET_MOUSEWHEEL, output_event->type()); - EXPECT_EQ(kTestData[i].flags(), output_event->flags()); - EXPECT_EQ(kTestData[i].location(), output_event->location()); - EXPECT_EQ(kTestData[i].root_location(), output_event->root_location()); - EXPECT_EQ(kTestData[i].offset(), output_event->offset()); - EXPECT_EQ(kTestData[i].time_stamp(), output_event->time_stamp()); + ExpectMouseWheelEventsEqual(kTestData[i], *output_event); } } -TEST_F(StructTraitsTest, FloatingPointLocations) { - ui::MouseEvent input_event = ui::MouseEvent( +TEST(StructTraitsTest, FloatingPointLocations) { + MouseEvent input_event( ET_MOUSE_PRESSED, gfx::Point(10, 10), gfx::Point(20, 30), base::TimeTicks() + base::TimeDelta::FromMicroseconds(201), EF_NONE, 0, PointerDetails(EventPointerType::POINTER_TYPE_MOUSE, MouseEvent::kMousePointerId)); - mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); input_event.set_location_f(gfx::PointF(10.1, 10.2)); input_event.set_root_location_f(gfx::PointF(20.2, 30.3)); + std::unique_ptr<Event> expected_copy = Event::Clone(input_event); std::unique_ptr<Event> output; - proxy->EchoEvent(Event::Clone(input_event), &output); + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(&expected_copy, + &output)); ASSERT_TRUE(output->IsMouseEvent()); ExpectEventsEqual(input_event, *output->AsMouseEvent()); } -TEST_F(StructTraitsTest, KeyEventPropertiesSerialized) { +TEST(StructTraitsTest, KeyEventPropertiesSerialized) { KeyEvent key_event(ET_KEY_PRESSED, VKEY_T, EF_NONE); const std::string key = "key"; const std::vector<uint8_t> value(0xCD, 2); @@ -374,7 +358,7 @@ EXPECT_EQ(properties, *(deserialized->AsKeyEvent()->properties())); } -TEST_F(StructTraitsTest, GestureEvent) { +TEST(StructTraitsTest, GestureEvent) { const GestureEvent kTestData[] = { {10, 20, EF_NONE, base::TimeTicks() + base::TimeDelta::FromMicroseconds(401), @@ -384,10 +368,11 @@ GestureEventDetails(ET_GESTURE_TAP)}, }; - mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); for (size_t i = 0; i < base::size(kTestData); i++) { + std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); std::unique_ptr<Event> output; - proxy->EchoEvent(Event::Clone(kTestData[i]), &output); + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>( + &expected_copy, &output)); EXPECT_TRUE(output->IsGestureEvent()); const GestureEvent* output_ptr_event = output->AsGestureEvent(); @@ -398,7 +383,7 @@ } } -TEST_F(StructTraitsTest, ScrollEvent) { +TEST(StructTraitsTest, ScrollEvent) { const ScrollEvent kTestData[] = { {ET_SCROLL, gfx::Point(10, 20), base::TimeTicks() + base::TimeDelta::FromMicroseconds(501), EF_NONE, 1, @@ -430,10 +415,11 @@ 2, 3, 4, 5, EventMomentumPhase::END, ScrollEventPhase::kNone}, }; - mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); for (size_t i = 0; i < base::size(kTestData); i++) { + std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); std::unique_ptr<Event> output; - proxy->EchoEvent(Event::Clone(kTestData[i]), &output); + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>( + &expected_copy, &output)); EXPECT_TRUE(output->IsScrollEvent()); const ScrollEvent* output_ptr_event = output->AsScrollEvent(); @@ -450,7 +436,7 @@ } } -TEST_F(StructTraitsTest, PointerDetails) { +TEST(StructTraitsTest, PointerDetails) { const PointerDetails kTestData[] = { {EventPointerType::POINTER_TYPE_UNKNOWN, 1, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f}, {EventPointerType::POINTER_TYPE_MOUSE, 1, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f}, @@ -467,13 +453,13 @@ input.offset.set_y(i + 1); PointerDetails output; - ASSERT_TRUE(mojo::test::SerializeAndDeserialize<ui::mojom::PointerDetails>( + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::PointerDetails>( &input, &output)); EXPECT_EQ(input, output); } } -TEST_F(StructTraitsTest, TouchEvent) { +TEST(StructTraitsTest, TouchEvent) { const TouchEvent kTestData[] = { {ET_TOUCH_RELEASED, {1, 2}, @@ -488,7 +474,7 @@ for (size_t i = 0; i < base::size(kTestData); i++) { std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]); std::unique_ptr<Event> output; - ASSERT_TRUE(mojo::test::SerializeAndDeserialize<ui::mojom::Event>( + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>( &expected_copy, &output)); ExpectEventsEqual(*expected_copy, *output); } @@ -501,20 +487,20 @@ touch_event->set_hovering(true); std::unique_ptr<Event> expected = std::move(touch_event); std::unique_ptr<Event> output; - ASSERT_TRUE(mojo::test::SerializeAndDeserialize<ui::mojom::Event>(&expected, - &output)); + ASSERT_TRUE( + mojo::test::SerializeAndDeserialize<mojom::Event>(&expected, &output)); ExpectEventsEqual(*expected, *output); } -TEST_F(StructTraitsTest, UnserializedTouchEventFields) { +TEST(StructTraitsTest, UnserializedTouchEventFields) { std::unique_ptr<TouchEvent> touch_event = std::make_unique<TouchEvent>(ET_TOUCH_CANCELLED, gfx::Point(), base::TimeTicks::Now(), PointerDetails()); touch_event->set_should_remove_native_touch_id_mapping(true); std::unique_ptr<Event> expected = std::move(touch_event); std::unique_ptr<Event> output; - ASSERT_TRUE(mojo::test::SerializeAndDeserialize<ui::mojom::Event>(&expected, - &output)); + ASSERT_TRUE( + mojo::test::SerializeAndDeserialize<mojom::Event>(&expected, &output)); ExpectEventsEqual(*expected, *output); // Have to set this back to false, else the destructor tries to access // state not setup in tests.
diff --git a/ui/events/mojo/traits_test_service.mojom b/ui/events/mojo/traits_test_service.mojom deleted file mode 100644 index 1df4cbe..0000000 --- a/ui/events/mojo/traits_test_service.mojom +++ /dev/null
@@ -1,12 +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. - -module ui.mojom; - -import "ui/events/mojo/event.mojom"; - -interface TraitsTestService { - [Sync] - EchoEvent(Event e) => (Event pass); -};
diff --git a/ui/file_manager/gallery/js/gallery.js b/ui/file_manager/gallery/js/gallery.js index 5cee684..34ddcf0 100644 --- a/ui/file_manager/gallery/js/gallery.js +++ b/ui/file_manager/gallery/js/gallery.js
@@ -814,6 +814,9 @@ selectedItem.touch(); this.dataModel_.evictCache(); + // Filename Edit field shows for anything selected. + this.filenameEdit_.hidden = false; + // Update the title and the display name. if (numSelectedItems === 1) { document.title = this.selectedEntry_.name; @@ -841,6 +844,7 @@ } } else { document.title = ''; + this.filenameEdit_.hidden = true; this.filenameEdit_.disabled = true; this.filenameEdit_.value = ''; this.resizeRenameField_();
diff --git a/ui/file_manager/integration_tests/file_manager/quick_view.js b/ui/file_manager/integration_tests/file_manager/quick_view.js index 140855b..5391ab5f 100644 --- a/ui/file_manager/integration_tests/file_manager/quick_view.js +++ b/ui/file_manager/integration_tests/file_manager/quick_view.js
@@ -256,6 +256,57 @@ }; /** + * Tests opening Quick View on a Crostini file. + */ +testcase.openQuickViewCrostini = function() { + let appId; + + const fakeLinuxFiles = '#directory-tree [root-type-icon="crostini"]'; + const realLinuxFiles = '#directory-tree [volume-type-icon="crostini"]'; + + StepsRunner.run([ + // Open Files app on Downloads containing ENTRIES.photos. + function() { + setupAndWaitUntilReady( + null, RootPath.DOWNLOADS, this.next, [ENTRIES.photos], []); + }, + // Check: the fake Linux files icon should be shown. + function(results) { + appId = results.windowId; + remoteCall.waitForElement(appId, fakeLinuxFiles).then(this.next); + }, + // Add files to the Crostini volume. + function() { + addEntries(['crostini'], BASIC_CROSTINI_ENTRY_SET, this.next); + }, + // Click the fake Linux files icon to mount the Crostini volume. + function() { + remoteCall.callRemoteTestUtil( + 'fakeMouseClick', appId, [fakeLinuxFiles], this.next); + }, + // Check: the Crostini volume icon should appear. + function(result) { + chrome.test.assertTrue(!!result, 'fakeMouseClick failed'); + remoteCall.waitForElement(appId, realLinuxFiles).then(this.next); + }, + // Check: the Crostini files should appear in the file list. + function() { + const files = TestEntryInfo.getExpectedRows(BASIC_CROSTINI_ENTRY_SET); + remoteCall.waitForFiles(appId, files, {ignoreLastModifiedTime: true}) + .then(this.next); + }, + // Open a Crostini file in Quick View. + function() { + const openSteps = openQuickViewSteps(appId, ENTRIES.hello.nameText); + StepsRunner.run(openSteps).then(this.next); + }, + function() { + checkIfNoErrorsOccured(this.next); + }, + ]); +}; + +/** * Tests opening Quick View and scrolling its <webview> which contains a tall * text document. */ @@ -420,7 +471,7 @@ const webView = ['#quick-view', '#dialog[open] webview.content']; StepsRunner.run([ - // Open Files app on Downloads containing ENTRIES.tallText. + // Open Files app on Downloads containing ENTRIES.tallPdf. function() { setupAndWaitUntilReady( null, RootPath.DOWNLOADS, this.next, [ENTRIES.tallPdf], []); @@ -467,7 +518,7 @@ // Check: the <webview> embed type should be PDF mime type. function(type) { chrome.test.assertEq('application/pdf', type); - checkIfNoErrorsOccured(this.next); + this.next(); }, function() { checkIfNoErrorsOccured(this.next);
diff --git a/ui/file_manager/integration_tests/gallery/open_image_files.js b/ui/file_manager/integration_tests/gallery/open_image_files.js index b6e69b53..4345a49 100644 --- a/ui/file_manager/integration_tests/gallery/open_image_files.js +++ b/ui/file_manager/integration_tests/gallery/open_image_files.js
@@ -161,3 +161,27 @@ testcase.openMultipleImagesAndChangeToSlideModeOnDownloads = function() { return openMultipleImagesAndChangeToSlideMode('local', 'downloads'); }; + +/** + * Runs a test to check whether the rename-input field is hidden after + * deleting the only selected image in the gallery. + * @return {Promise} Promise to be fulfilled with on success. + */ +testcase.deleteSingleOpenPhotoOnDownloads = () => { + const launchedPromise = launch('local', 'downloads', [ENTRIES.desktop]); + let appId; + return launchedPromise.then(args => { + appId = args.appId; + return gallery.waitForSlideImage(appId, 800, 600, 'My Desktop Background'); + }).then(() => { + // Click the delete button. + return gallery.waitAndClickElement(appId, 'button.delete'); + }).then(result => { + chrome.test.assertTrue(!!result); + // Wait and click delete button of confirmation dialog. + return gallery.waitAndClickElement(appId, '.cr-dialog-ok'); + }).then(() => { + // Check: The edit name field should hide. + return gallery.waitForElement(appId, '#rename-input[hidden]'); + }); +}; \ No newline at end of file
diff --git a/ui/file_manager/integration_tests/gallery/thumbnail_mode.js b/ui/file_manager/integration_tests/gallery/thumbnail_mode.js index 010b73d5..0353efd 100644 --- a/ui/file_manager/integration_tests/gallery/thumbnail_mode.js +++ b/ui/file_manager/integration_tests/gallery/thumbnail_mode.js
@@ -118,6 +118,9 @@ chrome.test.assertTrue(!!result); // Wait until error banner is shown. return gallery.waitForElement(appId, '.gallery[error] .error-banner'); + }).then(function() { + // Check: The edit name field should hide. + return gallery.waitForElement(appId, '#rename-input[hidden]'); }); } @@ -161,6 +164,9 @@ // Confirm slideshow button is disabled. return gallery.waitForElement(appId, 'button.slideshow[disabled]'); }).then(function() { + // Check: The edit name field should hide. + return gallery.waitForElement(appId, '#rename-input[hidden]'); + }).then(function() { // Switch back to slide mode by clicking mode button. return gallery.waitAndClickElement(appId, 'button.mode:not([disabled])'); }).then(function(result) {
diff --git a/ui/gfx/color_palette.h b/ui/gfx/color_palette.h index 0d55ae0a..4a465f55 100644 --- a/ui/gfx/color_palette.h +++ b/ui/gfx/color_palette.h
@@ -22,6 +22,7 @@ constexpr SkColor kGoogleBlue900 = SkColorSetRGB(0x17, 0x4E, 0xA6); constexpr SkColor kGoogleBlueDark600 = SkColorSetRGB(0x25, 0x81, 0xDF); constexpr SkColor kGoogleRed300 = SkColorSetRGB(0xF2, 0x8B, 0xB2); +constexpr SkColor kGoogleRed500 = SkColorSetRGB(0xEA, 0x43, 0x35); constexpr SkColor kGoogleRed600 = SkColorSetRGB(0xD9, 0x30, 0x25); constexpr SkColor kGoogleRed700 = SkColorSetRGB(0xC5, 0x22, 0x1F); constexpr SkColor kGoogleRed800 = SkColorSetRGB(0xB3, 0x14, 0x12);
diff --git a/ui/gfx/mojo/selection_bound.typemap b/ui/gfx/mojo/selection_bound.typemap index e2b16f7..d6bb094 100644 --- a/ui/gfx/mojo/selection_bound.typemap +++ b/ui/gfx/mojo/selection_bound.typemap
@@ -6,3 +6,6 @@ public_headers = [ "//ui/gfx/selection_bound.h" ] traits_headers = [ "//ui/gfx/mojo/selection_bound_struct_traits.h" ] type_mappings = [ "gfx.mojom.SelectionBound=gfx::SelectionBound" ] +deps = [ + "//ui/gfx/geometry/mojo:struct_traits", +]
diff --git a/ui/gfx/mojo/selection_bound_struct_traits.h b/ui/gfx/mojo/selection_bound_struct_traits.h index f4ba831..681de71 100644 --- a/ui/gfx/mojo/selection_bound_struct_traits.h +++ b/ui/gfx/mojo/selection_bound_struct_traits.h
@@ -5,6 +5,7 @@ #ifndef UI_GFX_MOJO_SELECTION_BOUND_STRUCT_TRAITS_H_ #define UI_GFX_MOJO_SELECTION_BOUND_STRUCT_TRAITS_H_ +#include "ui/gfx/geometry/mojo/geometry_struct_traits.h" #include "ui/gfx/mojo/selection_bound.mojom-shared.h" #include "ui/gfx/selection_bound.h"
diff --git a/ui/latency/mojo/BUILD.gn b/ui/latency/mojo/BUILD.gn index e8e2ba30..17c27b1 100644 --- a/ui/latency/mojo/BUILD.gn +++ b/ui/latency/mojo/BUILD.gn
@@ -11,7 +11,6 @@ public_deps = [ "//mojo/public/mojom/base", - "//ui/gfx/geometry/mojo", ] }
diff --git a/ui/latency/mojo/DEPS b/ui/latency/mojo/DEPS index 77a2762..733587e 100644 --- a/ui/latency/mojo/DEPS +++ b/ui/latency/mojo/DEPS
@@ -1,5 +1,4 @@ include_rules = [ "+mojo/public", - "+ui/gfx/geometry/mojo", "+ui/latency", ]
diff --git a/ui/latency/mojo/latency_info.mojom b/ui/latency/mojo/latency_info.mojom index a39a8ed..ee082c71 100644 --- a/ui/latency/mojo/latency_info.mojom +++ b/ui/latency/mojo/latency_info.mojom
@@ -5,7 +5,6 @@ module ui.mojom; import "mojo/public/mojom/base/time.mojom"; -import "ui/gfx/geometry/mojo/geometry.mojom"; enum LatencyComponentType { // ---------------------------BEGIN COMPONENT-------------------------------
diff --git a/ui/latency/mojo/latency_info.typemap b/ui/latency/mojo/latency_info.typemap index 53c9bf6..4450bfe 100644 --- a/ui/latency/mojo/latency_info.typemap +++ b/ui/latency/mojo/latency_info.typemap
@@ -13,7 +13,6 @@ "latency_info_struct_traits.h", ] public_deps = [ - "//ui/gfx/geometry/mojo:struct_traits", "//ui/latency", ] deps = [
diff --git a/ui/latency/mojo/latency_info_struct_traits.h b/ui/latency/mojo/latency_info_struct_traits.h index e668e4d..00ab6f2 100644 --- a/ui/latency/mojo/latency_info_struct_traits.h +++ b/ui/latency/mojo/latency_info_struct_traits.h
@@ -5,7 +5,6 @@ #ifndef UI_LATENCY_MOJO_LATENCY_INFO_STRUCT_TRAITS_H_ #define UI_LATENCY_MOJO_LATENCY_INFO_STRUCT_TRAITS_H_ -#include "ui/gfx/geometry/mojo/geometry_struct_traits.h" #include "ui/latency/latency_info.h" #include "ui/latency/mojo/latency_info.mojom-shared.h"
diff --git a/ui/ozone/platform/scenic/ozone_platform_scenic.cc b/ui/ozone/platform/scenic/ozone_platform_scenic.cc index 2684a83..fde7eea 100644 --- a/ui/ozone/platform/scenic/ozone_platform_scenic.cc +++ b/ui/ozone/platform/scenic/ozone_platform_scenic.cc
@@ -4,9 +4,14 @@ #include "ui/ozone/platform/scenic/ozone_platform_scenic.h" +#include <memory> +#include <utility> +#include <vector> + #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop_current.h" #include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h" #include "ui/display/manager/fake_display_delegate.h" #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" @@ -46,13 +51,15 @@ }; // OzonePlatform for Scenic. -class OzonePlatformScenic : public OzonePlatform { +class OzonePlatformScenic + : public OzonePlatform, + public base::MessageLoopCurrent::DestructionObserver { public: - OzonePlatformScenic() : surface_factory_(&window_manager_) {} + OzonePlatformScenic() + : window_manager_(std::make_unique<ScenicWindowManager>()), + surface_factory_(window_manager_.get()) {} ~OzonePlatformScenic() override = default; - ScenicWindowManager* window_manager() { return &window_manager_; } - // OzonePlatform implementation. ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override { return &surface_factory_; @@ -87,7 +94,8 @@ return nullptr; } return std::make_unique<ScenicWindow>( - &window_manager_, delegate, std::move(properties.view_owner_request)); + window_manager_.get(), delegate, + std::move(properties.view_owner_request)); } const PlatformProperties& GetPlatformProperties() override { @@ -101,7 +109,7 @@ } std::unique_ptr<PlatformScreen> CreateScreen() override { - return window_manager_.CreateScreen(); + return window_manager_->CreateScreen(); } void InitializeUI(const InitParams& params) override { @@ -114,12 +122,20 @@ input_controller_ = CreateStubInputController(); cursor_factory_ozone_ = std::make_unique<BitmapCursorFactoryOzone>(); gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost()); + + base::MessageLoopCurrent::Get()->AddDestructionObserver(this); } void InitializeGPU(const InitParams& params) override {} private: - ScenicWindowManager window_manager_; + // Performs graceful cleanup tasks on main message loop teardown. + void Shutdown() { window_manager_.reset(); } + + // base::MessageLoopCurrent::DestructionObserver implementation. + void WillDestroyCurrentMessageLoop() override { Shutdown(); } + + std::unique_ptr<ScenicWindowManager> window_manager_; ScenicSurfaceFactory surface_factory_; std::unique_ptr<PlatformEventSource> platform_event_source_;
diff --git a/ui/ozone/platform/scenic/scenic_window.cc b/ui/ozone/platform/scenic/scenic_window.cc index 28a9b23..c8622cd 100644 --- a/ui/ozone/platform/scenic/scenic_window.cc +++ b/ui/ozone/platform/scenic/scenic_window.cc
@@ -260,7 +260,6 @@ bool result = false; if (event.is_focus()) { - LOG(ERROR) << "RECEIVED FOCUS EVENT!"; delegate_->OnActivationChanged(event.focus().focused); result = true; } else {
diff --git a/ui/ozone/platform/scenic/scenic_window_manager.cc b/ui/ozone/platform/scenic/scenic_window_manager.cc index 9db874b..cf900fe 100644 --- a/ui/ozone/platform/scenic/scenic_window_manager.cc +++ b/ui/ozone/platform/scenic/scenic_window_manager.cc
@@ -5,6 +5,7 @@ #include "ui/ozone/platform/scenic/scenic_window_manager.h" #include "base/fuchsia/component_context.h" +#include "ui/ozone/platform/scenic/ozone_platform_scenic.h" namespace ui { @@ -22,8 +23,9 @@ if (!view_manager_) { view_manager_ = base::fuchsia::ComponentContext::GetDefault() ->ConnectToService<fuchsia::ui::viewsv1::ViewManager>(); - view_manager_.set_error_handler( - [this]() { LOG(FATAL) << "ViewManager connection failed."; }); + view_manager_.set_error_handler([this]() { + LOG(ERROR) << "The ViewManager channel was unexpectedly terminated."; + }); } return view_manager_.get(); @@ -32,8 +34,9 @@ fuchsia::ui::scenic::Scenic* ScenicWindowManager::GetScenic() { if (!scenic_) { GetViewManager()->GetScenic(scenic_.NewRequest()); - scenic_.set_error_handler( - [this]() { LOG(FATAL) << "Scenic connection failed."; }); + scenic_.set_error_handler([this]() { + LOG(ERROR) << "The Scenic channel was unexpectedly terminated."; + }); } return scenic_.get(); }
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index a57f45a..b7fa6d3 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -95,6 +95,7 @@ "color_chooser/color_chooser_view.h", "context_menu_controller.h", "controls/animated_icon_view.h", + "controls/animated_image_view.h", "controls/button/blue_button.h", "controls/button/button.h", "controls/button/checkbox.h", @@ -112,6 +113,7 @@ "controls/focus_ring.h", "controls/focusable_border.h", "controls/image_view.h", + "controls/image_view_base.h", "controls/label.h", "controls/link.h", "controls/link_listener.h", @@ -292,6 +294,7 @@ "button_drag_utils.cc", "color_chooser/color_chooser_view.cc", "controls/animated_icon_view.cc", + "controls/animated_image_view.cc", "controls/button/blue_button.cc", "controls/button/button.cc", "controls/button/checkbox.cc", @@ -307,6 +310,7 @@ "controls/focus_ring.cc", "controls/focusable_border.cc", "controls/image_view.cc", + "controls/image_view_base.cc", "controls/label.cc", "controls/link.cc", "controls/menu/display_change_listener_mac.cc",
diff --git a/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc b/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc index 2e78f27..aa9e497 100644 --- a/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc +++ b/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
@@ -310,7 +310,7 @@ EXPECT_EQ(height, height3); } -TEST_F(AXSystemCaretWinTest, TestCaretMSAAEvents) { +TEST_F(AXSystemCaretWinTest, DISABLED_TestCaretMSAAEvents) { TextfieldTestApi textfield_test_api(textfield_); Microsoft::WRL::ComPtr<IAccessible> caret_accessible; gfx::NativeWindow native_window = widget_->GetNativeWindow();
diff --git a/ui/views/controls/animated_image_view.cc b/ui/views/controls/animated_image_view.cc new file mode 100644 index 0000000..2d56a88 --- /dev/null +++ b/ui/views/controls/animated_image_view.cc
@@ -0,0 +1,139 @@ +// 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 "ui/views/controls/animated_image_view.h" + +#include <utility> + +#include "base/logging.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/skottie_wrapper.h" +#include "ui/views/widget/widget.h" + +namespace views { +namespace { + +bool AreAnimatedImagesEqual(const gfx::SkiaVectorAnimation& animation_1, + const gfx::SkiaVectorAnimation& animation_2) { + // In rare cases this may return false, even if the animated images are backed + // by the same resource file. + return animation_1.skottie() == animation_2.skottie(); +} + +} // namespace + +AnimatedImageView::AnimatedImageView() = default; + +AnimatedImageView::~AnimatedImageView() = default; + +void AnimatedImageView::SetAnimatedImage( + std::unique_ptr<gfx::SkiaVectorAnimation> animated_image) { + if (animated_image_ && + AreAnimatedImagesEqual(*animated_image, *animated_image_)) { + Stop(); + return; + } + + gfx::Size preferred_size(GetPreferredSize()); + animated_image_ = std::move(animated_image); + + // Stop the animation to reset it. + Stop(); + + if (preferred_size != GetPreferredSize()) + PreferredSizeChanged(); + SchedulePaint(); +} + +void AnimatedImageView::Play() { + DCHECK(animated_image_); + DCHECK_EQ(state_, State::kStopped); + + state_ = State::kPlaying; + + // We cannot play the animation unless we have a valid compositor. + if (!compositor_) + return; + + // Ensure the class is added as an observer to receive clock ticks. + if (!compositor_->HasAnimationObserver(this)) + compositor_->AddAnimationObserver(this); + + animated_image_->Start(); +} + +void AnimatedImageView::Stop() { + DCHECK(animated_image_); + if (compositor_) + compositor_->RemoveAnimationObserver(this); + + animated_image_->Stop(); + state_ = State::kStopped; +} + +gfx::Size AnimatedImageView::GetImageSize() const { + return image_size_.value_or( + animated_image_ ? animated_image_->GetOriginalSize() : gfx::Size()); +} + +void AnimatedImageView::OnPaint(gfx::Canvas* canvas) { + View::OnPaint(canvas); + if (!animated_image_) + return; + canvas->Save(); + canvas->Translate(GetImageBounds().origin().OffsetFromOrigin()); + + // OnPaint may be called before clock tick was received; in that case just + // paint the first frame. + if (!previous_timestamp_.is_null() && state_ != State::kStopped) + animated_image_->Paint(canvas, previous_timestamp_, GetImageSize()); + else + animated_image_->PaintFrame(canvas, 0, GetImageSize()); + + canvas->Restore(); +} + +const char* AnimatedImageView::GetClassName() const { + return "AnimatedImageView"; +} + +void AnimatedImageView::NativeViewHierarchyChanged() { + // When switching a window from one display to another, the compositor + // associated with the widget changes. + AddedToWidget(); +} + +void AnimatedImageView::AddedToWidget() { + ui::Compositor* compositor = GetWidget()->GetCompositor(); + DCHECK(compositor); + if (compositor_ != compositor) { + if (compositor_ && compositor_->HasAnimationObserver(this)) + compositor_->RemoveAnimationObserver(this); + compositor_ = compositor; + } +} + +void AnimatedImageView::RemovedFromWidget() { + if (compositor_) { + Stop(); + if (compositor_->HasAnimationObserver(this)) + compositor_->RemoveAnimationObserver(this); + compositor_ = nullptr; + } +} + +void AnimatedImageView::OnAnimationStep(base::TimeTicks timestamp) { + previous_timestamp_ = timestamp; + SchedulePaint(); +} + +void AnimatedImageView::OnCompositingShuttingDown(ui::Compositor* compositor) { + if (compositor_ == compositor) { + Stop(); + compositor_->RemoveAnimationObserver(this); + compositor_ = nullptr; + } +} + +} // namespace views
diff --git a/ui/views/controls/animated_image_view.h b/ui/views/controls/animated_image_view.h new file mode 100644 index 0000000..c62fe5c --- /dev/null +++ b/ui/views/controls/animated_image_view.h
@@ -0,0 +1,91 @@ +// 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 UI_VIEWS_CONTROLS_ANIMATED_IMAGE_VIEW_H_ +#define UI_VIEWS_CONTROLS_ANIMATED_IMAGE_VIEW_H_ + +#include <memory> + +#include "base/macros.h" +#include "ui/gfx/skia_vector_animation.h" +#include "ui/views/controls/image_view_base.h" + +namespace gfx { +class SkiaVectorAnimation; +class Canvas; +} // namespace gfx + +namespace ui { +class Compositor; +} + +namespace views { + +///////////////////////////////////////////////////////////////////////////// +// +// AnimatedImageView class. +// +// An AnimatedImageView can display a skia vector animation. The animation paint +// size can be set via SetImageSize. The animation is stopped by default. +// Use this over AnimatedIconView if you want to play a skottie animation file. +// +///////////////////////////////////////////////////////////////////////////// +class VIEWS_EXPORT AnimatedImageView : public ImageViewBase, + public ui::CompositorAnimationObserver { + public: + enum class State { + kPlaying, // The animation is currently playing. + kStopped // The animation is stopped and paint will raster the first + // frame. + }; + + AnimatedImageView(); + ~AnimatedImageView() override; + + // Set the animated image that should be displayed. Setting an animated image + // will result in stopping the current animation. + void SetAnimatedImage( + std::unique_ptr<gfx::SkiaVectorAnimation> animated_image); + + // Plays the animation in loop. + void Play(); + + // Stops any animation and resets it to the start frame. + void Stop(); + + private: + friend class AnimatedImageViewTest; + + // Overridden from View: + void OnPaint(gfx::Canvas* canvas) override; + const char* GetClassName() const override; + void NativeViewHierarchyChanged() override; + void AddedToWidget() override; + void RemovedFromWidget() override; + + // Overridden from ui::CompositorAnimationObserver: + void OnAnimationStep(base::TimeTicks timestamp) override; + void OnCompositingShuttingDown(ui::Compositor* compositor) override; + + // Overridden from ImageViewBase: + gfx::Size GetImageSize() const override; + + // The current state of the animation. + State state_ = State::kStopped; + + // The compositor associated with the widget of this view. + ui::Compositor* compositor_ = nullptr; + + // The most recent timestamp at which a paint was scheduled for this view. + base::TimeTicks previous_timestamp_; + + // The underlying skia vector animation. + std::unique_ptr<gfx::SkiaVectorAnimation> animated_image_; + + DISALLOW_COPY_AND_ASSIGN(AnimatedImageView); +}; + +} // namespace views + +#endif // UI_VIEWS_CONTROLS_ANIMATED_IMAGE_VIEW_H_
diff --git a/ui/views/controls/image_view.cc b/ui/views/controls/image_view.cc index 1eb38138..2e9c406 100644 --- a/ui/views/controls/image_view.cc +++ b/ui/views/controls/image_view.cc
@@ -7,12 +7,9 @@ #include <utility> #include "base/logging.h" -#include "base/strings/utf_string_conversions.h" #include "cc/paint/paint_flags.h" #include "skia/ext/image_operations.h" -#include "ui/accessibility/ax_node_data.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/insets.h" namespace views { @@ -29,13 +26,9 @@ // static const char ImageView::kViewClassName[] = "ImageView"; -ImageView::ImageView() - : horizontal_alignment_(CENTER), - vertical_alignment_(CENTER), - last_paint_scale_(0.f), - last_painted_bitmap_pixels_(nullptr) {} +ImageView::ImageView() = default; -ImageView::~ImageView() {} +ImageView::~ImageView() = default; void ImageView::SetImage(const gfx::ImageSkia& img) { if (IsImageEqual(img)) @@ -63,20 +56,6 @@ return image_; } -void ImageView::SetImageSize(const gfx::Size& image_size) { - image_size_ = image_size; - PreferredSizeChanged(); -} - -gfx::Rect ImageView::GetImageBounds() const { - gfx::Size image_size = GetImageSize(); - return gfx::Rect(ComputeImageOrigin(image_size), image_size); -} - -void ImageView::ResetImageSize() { - image_size_.reset(); -} - bool ImageView::IsImageEqual(const gfx::ImageSkia& img) const { // Even though we copy ImageSkia in SetImage() the backing store // (ImageSkiaStorage) is not copied and may have changed since the last call @@ -92,130 +71,15 @@ return image_size_.value_or(image_.size()); } -gfx::Point ImageView::ComputeImageOrigin(const gfx::Size& image_size) const { - gfx::Insets insets = GetInsets(); - - int x = 0; - // In order to properly handle alignment of images in RTL locales, we need - // to flip the meaning of trailing and leading. For example, if the - // horizontal alignment is set to trailing, then we'll use left alignment for - // the image instead of right alignment if the UI layout is RTL. - Alignment actual_horizontal_alignment = horizontal_alignment_; - if (base::i18n::IsRTL() && (horizontal_alignment_ != CENTER)) { - actual_horizontal_alignment = - (horizontal_alignment_ == LEADING) ? TRAILING : LEADING; - } - switch (actual_horizontal_alignment) { - case LEADING: - x = insets.left(); - break; - case TRAILING: - x = width() - insets.right() - image_size.width(); - break; - case CENTER: - x = (width() - insets.width() - image_size.width()) / 2 + insets.left(); - break; - } - - int y = 0; - switch (vertical_alignment_) { - case LEADING: - y = insets.top(); - break; - case TRAILING: - y = height() - insets.bottom() - image_size.height(); - break; - case CENTER: - y = (height() - insets.height() - image_size.height()) / 2 + insets.top(); - break; - } - - return gfx::Point(x, y); -} - void ImageView::OnPaint(gfx::Canvas* canvas) { View::OnPaint(canvas); OnPaintImage(canvas); } -void ImageView::SetAccessibleName(const base::string16& accessible_name) { - accessible_name_ = accessible_name; -} - -base::string16 ImageView::GetAccessibleName() const { - return accessible_name_; -} - -void ImageView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ax::mojom::Role::kImage; - node_data->SetName(accessible_name_); -} - const char* ImageView::GetClassName() const { return kViewClassName; } -void ImageView::SetHorizontalAlignment(Alignment alignment) { - if (alignment != horizontal_alignment_) { - horizontal_alignment_ = alignment; - SchedulePaint(); - } -} - -ImageView::Alignment ImageView::GetHorizontalAlignment() const { - return horizontal_alignment_; -} - -void ImageView::SetVerticalAlignment(Alignment alignment) { - if (alignment != vertical_alignment_) { - vertical_alignment_ = alignment; - SchedulePaint(); - } -} - -ImageView::Alignment ImageView::GetVerticalAlignment() const { - return vertical_alignment_; -} - -// TODO(crbug.com/890465): Update the duplicate code here and in views::Button. -void ImageView::SetTooltipText(const base::string16& tooltip) { - tooltip_text_ = tooltip; - if (accessible_name_.empty()) - accessible_name_ = tooltip_text_; -} - -base::string16 ImageView::GetTooltipText() const { - return tooltip_text_; -} - -bool ImageView::GetTooltipText(const gfx::Point& p, - base::string16* tooltip) const { - if (tooltip_text_.empty()) - return false; - - *tooltip = GetTooltipText(); - return true; -} - -gfx::Size ImageView::CalculatePreferredSize() const { - gfx::Size size = GetImageSize(); - size.Enlarge(GetInsets().width(), GetInsets().height()); - return size; -} - -views::PaintInfo::ScaleType ImageView::GetPaintScaleType() const { - // ImageView contains an image which is rastered at the device scale factor. - // By default, the paint commands are recorded at a scale factor slightly - // different from the device scale factor. Re-rastering the image at this - // paint recording scale will result in a distorted image. Paint recording - // scale might also not be uniform along the x & y axis, thus resulting in - // further distortion in the aspect ratio of the final image. - // |kUniformScaling| ensures that the paint recording scale is uniform along - // the x & y axis and keeps the scale equal to the device scale factor. - // See http://crbug.com/754010 for more details. - return views::PaintInfo::ScaleType::kUniformScaling; -} - void ImageView::OnPaintImage(gfx::Canvas* canvas) { last_paint_scale_ = canvas->image_scale(); last_painted_bitmap_pixels_ = nullptr;
diff --git a/ui/views/controls/image_view.h b/ui/views/controls/image_view.h index b13e494..e80a97a 100644 --- a/ui/views/controls/image_view.h +++ b/ui/views/controls/image_view.h
@@ -6,9 +6,8 @@ #define UI_VIEWS_CONTROLS_IMAGE_VIEW_H_ #include "base/macros.h" -#include "base/optional.h" #include "ui/gfx/image/image_skia.h" -#include "ui/views/view.h" +#include "ui/views/controls/image_view_base.h" namespace gfx { class Canvas; @@ -26,17 +25,11 @@ // provided image size. // ///////////////////////////////////////////////////////////////////////////// -class VIEWS_EXPORT ImageView : public View { +class VIEWS_EXPORT ImageView : public ImageViewBase { public: // Internal class name. static const char kViewClassName[]; - enum Alignment { - LEADING = 0, - CENTER, - TRAILING - }; - ImageView(); ~ImageView() override; @@ -52,39 +45,13 @@ // The returned image is still owned by the ImageView. const gfx::ImageSkia& GetImage() const; - // Set the desired image size for the receiving ImageView. - void SetImageSize(const gfx::Size& image_size); - - // Returns the actual bounds of the visible image inside the view. - gfx::Rect GetImageBounds() const; - - // Reset the image size to the current image dimensions. - void ResetImageSize(); - - // Set / Get the horizontal alignment. - void SetHorizontalAlignment(Alignment ha); - Alignment GetHorizontalAlignment() const; - - // Set / Get the vertical alignment. - void SetVerticalAlignment(Alignment va); - Alignment GetVerticalAlignment() const; - - // Set / Get the tooltip text. - void SetTooltipText(const base::string16& tooltip); - base::string16 GetTooltipText() const; - - // Set / Get the accessible name text. - void SetAccessibleName(const base::string16& name); - base::string16 GetAccessibleName() const; - - // Overriden from View: + // Overridden from View: void OnPaint(gfx::Canvas* canvas) override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; const char* GetClassName() const override; - bool GetTooltipText(const gfx::Point& p, - base::string16* tooltip) const override; - gfx::Size CalculatePreferredSize() const override; - views::PaintInfo::ScaleType GetPaintScaleType() const override; + + protected: + // Overridden from ImageViewBase: + gfx::Size GetImageSize() const override; private: friend class ImageViewTest; @@ -99,40 +66,18 @@ // for this to return false even though the images are in fact equal. bool IsImageEqual(const gfx::ImageSkia& img) const; - // Returns the size the image will be painted. - gfx::Size GetImageSize() const; - - // Compute the image origin given the desired size and the receiver alignment - // properties. - gfx::Point ComputeImageOrigin(const gfx::Size& image_size) const; - - // The actual image size. - base::Optional<gfx::Size> image_size_; - // The underlying image. gfx::ImageSkia image_; // Caches the scaled image reps. gfx::ImageSkia scaled_image_; - // Horizontal alignment. - Alignment horizontal_alignment_; - - // Vertical alignment. - Alignment vertical_alignment_; - - // The current tooltip text. - base::string16 tooltip_text_; - - // The current accessible name text. - base::string16 accessible_name_; - // Scale last painted at. - float last_paint_scale_; + float last_paint_scale_ = 0.f; // Address of bytes we last painted. This is used only for comparison, so its // safe to cache. - void* last_painted_bitmap_pixels_; + void* last_painted_bitmap_pixels_ = nullptr; DISALLOW_COPY_AND_ASSIGN(ImageView); };
diff --git a/ui/views/controls/image_view_base.cc b/ui/views/controls/image_view_base.cc new file mode 100644 index 0000000..f942680 --- /dev/null +++ b/ui/views/controls/image_view_base.cc
@@ -0,0 +1,154 @@ +// 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 "ui/views/controls/image_view_base.h" + +#include <utility> + +#include "base/logging.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/gfx/geometry/insets.h" + +namespace views { + +ImageViewBase::ImageViewBase() = default; + +ImageViewBase::~ImageViewBase() = default; + +void ImageViewBase::SetImageSize(const gfx::Size& image_size) { + image_size_ = image_size; + image_origin_ = ComputeImageOrigin(GetImageSize()); + PreferredSizeChanged(); +} + +gfx::Rect ImageViewBase::GetImageBounds() const { + return gfx::Rect(image_origin_, GetImageSize()); +} + +void ImageViewBase::ResetImageSize() { + image_size_.reset(); + PreferredSizeChanged(); + image_origin_ = ComputeImageOrigin(GetImageSize()); +} + +gfx::Point ImageViewBase::ComputeImageOrigin( + const gfx::Size& image_size) const { + gfx::Insets insets = GetInsets(); + + int x = 0; + // In order to properly handle alignment of images in RTL locales, we need + // to flip the meaning of trailing and leading. For example, if the + // horizontal alignment is set to trailing, then we'll use left alignment for + // the image instead of right alignment if the UI layout is RTL. + Alignment actual_horizontal_alignment = horizontal_alignment_; + if (base::i18n::IsRTL() && (horizontal_alignment_ != CENTER)) { + actual_horizontal_alignment = + (horizontal_alignment_ == LEADING) ? TRAILING : LEADING; + } + switch (actual_horizontal_alignment) { + case LEADING: + x = insets.left(); + break; + case TRAILING: + x = width() - insets.right() - image_size.width(); + break; + case CENTER: + x = (width() - insets.width() - image_size.width()) / 2 + insets.left(); + break; + } + + int y = 0; + switch (vertical_alignment_) { + case LEADING: + y = insets.top(); + break; + case TRAILING: + y = height() - insets.bottom() - image_size.height(); + break; + case CENTER: + y = (height() - insets.height() - image_size.height()) / 2 + insets.top(); + break; + } + + return gfx::Point(x, y); +} + +void ImageViewBase::GetAccessibleNodeData(ui::AXNodeData* node_data) { + node_data->role = ax::mojom::Role::kImage; + node_data->SetName(tooltip_text_); +} + +void ImageViewBase::SetHorizontalAlignment(Alignment alignment) { + if (alignment != horizontal_alignment_) { + horizontal_alignment_ = alignment; + image_origin_ = ComputeImageOrigin(GetImageSize()); + SchedulePaint(); + } +} + +ImageViewBase::Alignment ImageViewBase::GetHorizontalAlignment() const { + return horizontal_alignment_; +} + +void ImageViewBase::SetVerticalAlignment(Alignment alignment) { + if (alignment != vertical_alignment_) { + vertical_alignment_ = alignment; + image_origin_ = ComputeImageOrigin(GetImageSize()); + SchedulePaint(); + } +} + +ImageViewBase::Alignment ImageViewBase::GetVerticalAlignment() const { + return vertical_alignment_; +} + +void ImageViewBase::SetAccessibleName(const base::string16& accessible_name) { + accessible_name_ = accessible_name; +} + +base::string16 ImageViewBase::GetAccessibleName() const { + return accessible_name_; +} + +void ImageViewBase::SetTooltipText(const base::string16& tooltip) { + tooltip_text_ = tooltip; +} + +base::string16 ImageViewBase::GetTooltipText() const { + return tooltip_text_; +} + +bool ImageViewBase::GetTooltipText(const gfx::Point& p, + base::string16* tooltip) const { + if (tooltip_text_.empty()) + return false; + + *tooltip = GetTooltipText(); + return true; +} + +gfx::Size ImageViewBase::CalculatePreferredSize() const { + gfx::Size size = GetImageSize(); + size.Enlarge(GetInsets().width(), GetInsets().height()); + return size; +} + +views::PaintInfo::ScaleType ImageViewBase::GetPaintScaleType() const { + // ImageViewBase contains an image which is rastered at the device scale + // factor. By default, the paint commands are recorded at a scale factor + // slightly different from the device scale factor. Re-rastering the image at + // this paint recording scale will result in a distorted image. Paint + // recording scale might also not be uniform along the x & y axis, thus + // resulting in further distortion in the aspect ratio of the final image. + // |kUniformScaling| ensures that the paint recording scale is uniform along + // the x & y axis and keeps the scale equal to the device scale factor. + // See http://crbug.com/754010 for more details. + return views::PaintInfo::ScaleType::kUniformScaling; +} + +void ImageViewBase::OnBoundsChanged(const gfx::Rect& previous_bounds) { + image_origin_ = ComputeImageOrigin(GetImageSize()); +} + +} // namespace views
diff --git a/ui/views/controls/image_view_base.h b/ui/views/controls/image_view_base.h new file mode 100644 index 0000000..250543d --- /dev/null +++ b/ui/views/controls/image_view_base.h
@@ -0,0 +1,94 @@ +// 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 UI_VIEWS_CONTROLS_IMAGE_VIEW_BASE_H_ +#define UI_VIEWS_CONTROLS_IMAGE_VIEW_BASE_H_ + +#include "base/macros.h" +#include "base/optional.h" +#include "ui/views/view.h" + +namespace gfx { +class Canvas; +} + +namespace views { + +class VIEWS_EXPORT ImageViewBase : public View { + public: + enum Alignment { LEADING, CENTER, TRAILING }; + + ImageViewBase(); + ~ImageViewBase() override; + + // Set the desired image size for the receiving ImageView. + void SetImageSize(const gfx::Size& image_size); + + // Returns the actual bounds of the visible image inside the view. + gfx::Rect GetImageBounds() const; + + // Reset the image size to the current image dimensions. + void ResetImageSize(); + + // Set / Get the horizontal alignment. + void SetHorizontalAlignment(Alignment ha); + Alignment GetHorizontalAlignment() const; + + // Set / Get the vertical alignment. + void SetVerticalAlignment(Alignment va); + Alignment GetVerticalAlignment() const; + + // Set / Get the tooltip text. + void SetTooltipText(const base::string16& tooltip); + base::string16 GetTooltipText() const; + + // Set / Get the accessible name text. + void SetAccessibleName(const base::string16& name); + base::string16 GetAccessibleName() const; + + // Overridden from View: + void OnPaint(gfx::Canvas* canvas) override = 0; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + const char* GetClassName() const override = 0; + bool GetTooltipText(const gfx::Point& p, + base::string16* tooltip) const override; + gfx::Size CalculatePreferredSize() const override; + views::PaintInfo::ScaleType GetPaintScaleType() const override; + void OnBoundsChanged(const gfx::Rect& previous_bounds) override; + + protected: + // Returns the size the image will be painted. + virtual gfx::Size GetImageSize() const = 0; + + // The requested image size. + base::Optional<gfx::Size> image_size_; + + // The origin of the image. + gfx::Point image_origin_; + + private: + friend class ImageViewTest; + + // Compute the image origin given the desired size and the receiver alignment + // properties. + gfx::Point ComputeImageOrigin(const gfx::Size& image_size) const; + + // Horizontal alignment. + Alignment horizontal_alignment_ = Alignment::CENTER; + + // Vertical alignment. + Alignment vertical_alignment_ = Alignment::CENTER; + + // The current tooltip text. + base::string16 tooltip_text_; + + // The current accessible name text. + base::string16 accessible_name_; + + DISALLOW_COPY_AND_ASSIGN(ImageViewBase); +}; + +} // namespace views + +#endif // UI_VIEWS_CONTROLS_IMAGE_VIEW_BASE_H_
diff --git a/ui/views/examples/BUILD.gn b/ui/views/examples/BUILD.gn index c757e20b..0069d8c 100644 --- a/ui/views/examples/BUILD.gn +++ b/ui/views/examples/BUILD.gn
@@ -9,6 +9,8 @@ testonly = true sources = [ + "animated_image_view_example.cc", + "animated_image_view_example.h", "box_layout_example.cc", "box_layout_example.h", "bubble_example.cc",
diff --git a/ui/views/examples/animated_image_view_example.cc b/ui/views/examples/animated_image_view_example.cc new file mode 100644 index 0000000..4e52a95 --- /dev/null +++ b/ui/views/examples/animated_image_view_example.cc
@@ -0,0 +1,143 @@ +// 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 "ui/views/examples/animated_image_view_example.h" + +#include <memory> + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/thread_restrictions.h" +#include "build/build_config.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/skottie_wrapper.h" +#include "ui/views/border.h" +#include "ui/views/controls/animated_image_view.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/md_text_button.h" +#include "ui/views/controls/textfield/textfield.h" +#include "ui/views/controls/textfield/textfield_controller.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/view.h" + +namespace views { +namespace examples { + +namespace { + +// This class can load a skottie(and lottie) animation file from disk and play +// it in a view as AnimatedImageView. +// See https://skia.org/user/modules/skottie for more info on skottie. +class AnimationGallery : public View, + public TextfieldController, + public ButtonListener { + public: + AnimationGallery() + : animated_image_view_(new AnimatedImageView()), + image_view_container_(new views::View()), + size_input_(new Textfield()), + file_chooser_(new Textfield()), + file_go_button_( + MdTextButton::Create(this, base::ASCIIToUTF16("Render"))) { + AddChildView(size_input_); + + image_view_container_->AddChildView(animated_image_view_); + image_view_container_->SetLayoutManager(std::make_unique<FillLayout>()); + animated_image_view_->SetBorder( + CreateSolidSidedBorder(1, 1, 1, 1, SK_ColorBLACK)); + AddChildView(image_view_container_); + + BoxLayout* box = SetLayoutManager( + std::make_unique<BoxLayout>(BoxLayout::kVertical, gfx::Insets(10), 10)); + box->SetFlexForView(image_view_container_, 1); + + file_chooser_->set_placeholder_text( + base::ASCIIToUTF16("Enter path to lottie JSON file")); + View* file_container = new View(); + BoxLayout* file_box = + file_container->SetLayoutManager(std::make_unique<BoxLayout>( + BoxLayout::kHorizontal, gfx::Insets(10), 10)); + file_container->AddChildView(file_chooser_); + file_container->AddChildView(file_go_button_); + file_box->SetFlexForView(file_chooser_, 1); + AddChildView(file_container); + + size_input_->set_placeholder_text( + base::ASCIIToUTF16("Size in dip (Empty for default)")); + size_input_->set_controller(this); + } + + ~AnimationGallery() override = default; + + // TextfieldController: + void ContentsChanged(Textfield* sender, + const base::string16& new_contents) override { + if (sender == size_input_) { + if (!base::StringToInt(new_contents, &size_) && (size_ > 0)) { + size_ = 0; + size_input_->SetText(base::string16()); + } + Update(); + } + } + + // ButtonListener: + void ButtonPressed(Button* sender, const ui::Event& event) override { + DCHECK_EQ(file_go_button_, sender); + std::string json; + base::ScopedAllowBlockingForTesting allow_blocking; +#if defined(OS_POSIX) + base::FilePath path(base::UTF16ToUTF8(file_chooser_->text())); +#else + base::FilePath path(file_chooser_->text()); +#endif // defined(OS_POSIX) + base::ReadFileToString(path, &json); + + auto skottie = base::MakeRefCounted<gfx::SkottieWrapper>( + base::RefCountedString::TakeString(&json)); + animated_image_view_->SetAnimatedImage( + std::make_unique<gfx::SkiaVectorAnimation>(skottie)); + animated_image_view_->Play(); + Update(); + } + + private: + void Update() { + if (size_ > 24) + animated_image_view_->SetImageSize(gfx::Size(size_, size_)); + else + animated_image_view_->ResetImageSize(); + Layout(); + } + + AnimatedImageView* animated_image_view_; + View* image_view_container_; + Textfield* size_input_; + Textfield* file_chooser_; + Button* file_go_button_; + + int size_ = 0; + + DISALLOW_COPY_AND_ASSIGN(AnimationGallery); +}; + +} // namespace + +AnimatedImageViewExample::AnimatedImageViewExample() + : ExampleBase("Animated Image View") {} + +AnimatedImageViewExample::~AnimatedImageViewExample() {} + +void AnimatedImageViewExample::CreateExampleView(View* container) { + container->SetLayoutManager(std::make_unique<FillLayout>()); + container->AddChildView(new AnimationGallery()); +} + +} // namespace examples +} // namespace views
diff --git a/ui/views/examples/animated_image_view_example.h b/ui/views/examples/animated_image_view_example.h new file mode 100644 index 0000000..8bf30b5 --- /dev/null +++ b/ui/views/examples/animated_image_view_example.h
@@ -0,0 +1,29 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_VIEWS_EXAMPLES_ANIMATED_IMAGE_VIEW_EXAMPLE_H_ +#define UI_VIEWS_EXAMPLES_ANIMATED_IMAGE_VIEW_EXAMPLE_H_ + +#include "base/macros.h" +#include "ui/views/examples/example_base.h" + +namespace views { +namespace examples { + +class VIEWS_EXAMPLES_EXPORT AnimatedImageViewExample : public ExampleBase { + public: + AnimatedImageViewExample(); + ~AnimatedImageViewExample() override; + + // ExampleBase: + void CreateExampleView(View* container) override; + + private: + DISALLOW_COPY_AND_ASSIGN(AnimatedImageViewExample); +}; + +} // namespace examples +} // namespace views + +#endif // UI_VIEWS_EXAMPLES_ANIMATED_IMAGE_VIEW_EXAMPLE_H_
diff --git a/ui/views/examples/examples_window.cc b/ui/views/examples/examples_window.cc index 0ceb1abd..683d5d59 100644 --- a/ui/views/examples/examples_window.cc +++ b/ui/views/examples/examples_window.cc
@@ -18,6 +18,7 @@ #include "ui/views/background.h" #include "ui/views/controls/combobox/combobox.h" #include "ui/views/controls/label.h" +#include "ui/views/examples/animated_image_view_example.h" #include "ui/views/examples/box_layout_example.h" #include "ui/views/examples/bubble_example.h" #include "ui/views/examples/button_example.h" @@ -58,6 +59,7 @@ // Creates the default set of examples. ExampleVector CreateExamples() { ExampleVector examples; + examples.push_back(std::make_unique<AnimatedImageViewExample>()); examples.push_back(std::make_unique<BoxLayoutExample>()); examples.push_back(std::make_unique<BubbleExample>()); examples.push_back(std::make_unique<ButtonExample>());
diff --git a/ui/webui/resources/cr_elements/cr_slider/cr_slider.html b/ui/webui/resources/cr_elements/cr_slider/cr_slider.html index a0a5253..f6203a2 100644 --- a/ui/webui/resources/cr_elements/cr_slider/cr_slider.html +++ b/ui/webui/resources/cr_elements/cr_slider/cr_slider.html
@@ -135,7 +135,7 @@ opacity: 1; } - .label { + #label { background: var(--google-blue-600); border-radius: 14px; bottom: 28px; @@ -180,7 +180,7 @@ <div id="bar"></div> <div id="markers" hidden$="[[!markerCount]]"> <template is="dom-repeat" items="[[getMarkers_(markerCount)]]"> - <div class$="[[getMarkerClass_(index, value, min, max, + <div class$="[[getMarkerClass_(index, immediateValue_, min, max, markerCount)]]"></div> </template> </div> @@ -189,9 +189,7 @@ <div id="knob" tabindex="0"></div> </div> <div id="labelContainer" aria-label="[[label_]]"> - <div id="label" class="label"> - <div id="labelText">[[label_]]</div> - </div> + <div id="label">[[label_]]</div> </div> </div> </template>
diff --git a/ui/webui/resources/cr_elements/cr_slider/cr_slider.js b/ui/webui/resources/cr_elements/cr_slider/cr_slider.js index 609b8ed..97033f5a 100644 --- a/ui/webui/resources/cr_elements/cr_slider/cr_slider.js +++ b/ui/webui/resources/cr_elements/cr_slider/cr_slider.js
@@ -89,6 +89,27 @@ type: Number, value: 0, notify: true, + observer: 'onValueChanged_', + }, + + /** + * If true, |value| is updated while dragging happens. If false, |value| + * is updated only once, when drag gesture finishes. + */ + updateValueInstantly: { + type: Boolean, + value: true, + }, + + /** + * |immediateValue_| has the most up-to-date value and is used to render + * the slider UI. When dragging, |immediateValue_| is always updated, and + * |value| is updated at least once when dragging is stopped. + * @private + */ + immediateValue_: { + type: Number, + value: 0, }, /** @private */ @@ -111,8 +132,8 @@ }, observers: [ - 'updateLabelAndAria_(value, min, max, ticks.*)', - 'updateKnobAndBar_(value, min, max)', + 'updateLabelAndAria_(immediateValue_, min, max)', + 'updateKnobAndBar_(immediateValue_, min, max)', ], listeners: { @@ -177,9 +198,18 @@ * @private */ getRatio_: function() { - const clamped = clamp(this.min, this.max, this.value); - this.value = this.snaps ? Math.round(clamped) : clamped; - return (this.value - this.min) / (this.max - this.min); + return (this.immediateValue_ - this.min) / (this.max - this.min); + }, + + /** @private */ + ensureValidValue_: function() { + if (this.immediateValue_ == undefined || this.value == undefined) + return; + let validValue = clamp(this.min, this.max, this.immediateValue_); + validValue = this.snaps ? Math.round(validValue) : validValue; + this.immediateValue_ = validValue; + if (!this.dragging || this.updateValueInstantly) + this.value = validValue; }, /** @@ -190,6 +220,7 @@ stopDragging_: function(pointerId) { this.dragging = false; this.draggingEventTracker_.removeAll(); + this.value = this.immediateValue_; // If there is a ripple animation in progress, setTimeout will hold off // on updating |holdDown_|. setTimeout(() => { @@ -297,6 +328,22 @@ this.max = this.ticks.length - 1; this.min = 0; } + this.ensureValidValue_(); + this.updateLabelAndAria_(); + }, + + /** + * Update |immediateValue_| which is used for rendering when |value| is + * updated either programmatically or from a keyboard input or a mouse drag + * (when |updateValueInstantly| is true). + * @private + */ + onValueChanged_: function() { + if (this.immediateValue_ == this.value) + return; + + this.immediateValue_ = this.value; + this.ensureValidValue_(); }, /** @private */ @@ -309,13 +356,13 @@ /** @private */ updateLabelAndAria_: function() { const ticks = this.ticks; - const index = this.value; + const index = this.immediateValue_; if (!ticks || ticks.length == 0 || index >= ticks.length || !Number.isInteger(index) || !this.snaps) { - this.setAttribute('aria-valuetext', this.value); + this.setAttribute('aria-valuetext', index); this.setAttribute('aria-valuemin', this.min); this.setAttribute('aria-valuemax', this.max); - this.setAttribute('aria-valuenow', this.value); + this.setAttribute('aria-valuenow', index); return; } const tick = ticks[index]; @@ -359,9 +406,8 @@ let ratio = (clientX - rect.left) / rect.width; if (this.isRtl_) ratio = 1 - ratio; - const newValue = ratio * (this.max - this.min) + this.min; - const clamped = clamp(this.min, this.max, newValue); - this.value = this.snaps ? Math.round(clamped) : clamped; + this.immediateValue_ = ratio * (this.max - this.min) + this.min; + this.ensureValidValue_(); }, _createRipple: function() {
diff --git a/webrunner/BUILD.gn b/webrunner/BUILD.gn index 7c4a04b..e544f7d 100644 --- a/webrunner/BUILD.gn +++ b/webrunner/BUILD.gn
@@ -174,6 +174,9 @@ test("webrunner_browsertests") { sources = [ "browser/context_impl_browsertest.cc", + "browser/frame_impl_browsertest.cc", + "browser/test_common.cc", + "browser/test_common.h", "browser/webrunner_browser_test.cc", "browser/webrunner_browser_test.h", "browser/webrunner_test_launcher.cc",
diff --git a/webrunner/browser/context_impl_browsertest.cc b/webrunner/browser/context_impl_browsertest.cc index d075a42..6df087af 100644 --- a/webrunner/browser/context_impl_browsertest.cc +++ b/webrunner/browser/context_impl_browsertest.cc
@@ -11,124 +11,42 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/common/url_constants.h" #include "net/cookies/cookie_store.h" -#include "net/test/embedded_test_server/embedded_test_server.h" -#include "net/test/embedded_test_server/http_request.h" #include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/url_constants.h" -#include "webrunner/browser/frame_impl.h" +#include "webrunner/browser/test_common.h" #include "webrunner/browser/webrunner_browser_test.h" -#include "webrunner/browser/webrunner_url_request_context_getter.h" #include "webrunner/service/common.h" namespace webrunner { using testing::_; -using testing::AllOf; using testing::Field; using testing::InvokeWithoutArgs; -using testing::Mock; -using chromium::web::NavigationEvent; +// Use a shorter name for NavigationEvent, because it is +// referenced frequently in this file. +using NavigationDetails = chromium::web::NavigationEvent; -const char kPage1Path[] = "/title1.html"; -const char kPage2Path[] = "/title2.html"; -const char kPage1Title[] = "title 1"; -const char kPage2Title[] = "title 2"; -const char kDataUrl[] = - "data:text/html;base64,PGI+SGVsbG8sIHdvcmxkLi4uPC9iPg=="; - -MATCHER(IsSet, "Checks if an optional field is set.") { - return !arg.is_null(); -} - -// Defines mock methods used by tests to observe NavigationStateChangeEvents -// and lower-level WebContentsObserver events. -class MockNavigationObserver : public chromium::web::NavigationEventObserver, - public content::WebContentsObserver { - public: - using content::WebContentsObserver::Observe; - - MockNavigationObserver() = default; - ~MockNavigationObserver() override = default; - - // Acknowledges processing of the most recent OnNavigationStateChanged call. - void Acknowledge() { - DCHECK(navigation_ack_callback_); - std::move(navigation_ack_callback_)(); - - // Pump the acknowledgement message over IPC. - base::RunLoop().RunUntilIdle(); - } - - MOCK_METHOD1(MockableOnNavigationStateChanged, - void(chromium::web::NavigationEvent change)); - - // chromium::web::NavigationEventObserver implementation. - // Proxies calls to MockableOnNavigationStateChanged(), because GMock does - // not work well with fit::Callbacks inside mocked actions. - void OnNavigationStateChanged( - chromium::web::NavigationEvent change, - OnNavigationStateChangedCallback callback) override { - MockableOnNavigationStateChanged(std::move(change)); - navigation_ack_callback_ = std::move(callback); - } - - // WebContentsObserver implementation. - MOCK_METHOD2(DidFinishLoad, - void(content::RenderFrameHost* render_frame_host, - const GURL& validated_url)); - - private: - OnNavigationStateChangedCallback navigation_ack_callback_; - - DISALLOW_COPY_AND_ASSIGN(MockNavigationObserver); -}; - +// Defines a suite of tests that exercise browser-level configuration and +// functionality. class ContextImplTest : public WebRunnerBrowserTest { public: ContextImplTest() : navigation_observer_binding_(&navigation_observer_) {} ~ContextImplTest() = default; - MOCK_METHOD1(OnServeHttpRequest, - void(const net::test_server::HttpRequest& request)); - protected: + // Creates a Frame with |navigation_observer_| attached. chromium::web::FramePtr CreateFrame() { - chromium::web::FramePtr frame; - context()->CreateFrame(frame.NewRequest()); - frame->SetNavigationEventObserver( - navigation_observer_binding_.NewBinding()); - base::RunLoop().RunUntilIdle(); - return frame; + return WebRunnerBrowserTest::CreateFrame(&navigation_observer_); } // Synchronously gets a list of cookies for this BrowserContext. net::CookieList GetCookies(); - // Navigates a |controller| to |url|, blocking until navigation is complete. - void CheckLoadUrl(const std::string& url, - const std::string& expected_title, - bool is_error, - chromium::web::NavigationController* controller) { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, - MockableOnNavigationStateChanged(testing::AllOf( - Field(&NavigationEvent::is_error, is_error), - Field(&NavigationEvent::title, expected_title), - Field(&NavigationEvent::url, url)))) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->LoadUrl(url, nullptr); - run_loop.Run(); - Mock::VerifyAndClearExpectations(this); - navigation_observer_.Acknowledge(); - } - void TearDownOnMainThread() override { navigation_observer_binding_.Unbind(); } @@ -141,471 +59,6 @@ DISALLOW_COPY_AND_ASSIGN(ContextImplTest); }; -class WebContentsDeletionObserver : public content::WebContentsObserver { - public: - explicit WebContentsDeletionObserver(content::WebContents* web_contents) - : content::WebContentsObserver(web_contents) {} - - MOCK_METHOD1(RenderViewDeleted, - void(content::RenderViewHost* render_view_host)); -}; - -// Verifies that the browser will navigate and generate a navigation observer -// event when LoadUrl() is called. -IN_PROC_BROWSER_TEST_F(ContextImplTest, NavigateFrame) { - chromium::web::FramePtr frame = CreateFrame(); - - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - CheckLoadUrl(url::kAboutBlankURL, url::kAboutBlankURL, false, - controller.get()); - - frame.Unbind(); -} - -// Tests that navigation errors are reported as navigation events, -// with the original URL that caused the error. -IN_PROC_BROWSER_TEST_F(ContextImplTest, NavigateError) { - chromium::web::FramePtr frame = CreateFrame(); - - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - CheckLoadUrl("http://unresolvable.foo.google.com/foo", - "unresolvable.foo.google.com/foo", true, controller.get()); - - CheckLoadUrl("http://unresolvable.foo.google.com/foo2", - "unresolvable.foo.google.com/foo2", true, controller.get()); - - CheckLoadUrl(url::kAboutBlankURL, url::kAboutBlankURL, false, - controller.get()); - - frame.Unbind(); -} - -IN_PROC_BROWSER_TEST_F(ContextImplTest, NavigateDataFrame) { - chromium::web::FramePtr frame = CreateFrame(); - - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - CheckLoadUrl(kDataUrl, kDataUrl, false, controller.get()); - - frame.Unbind(); -} - -IN_PROC_BROWSER_TEST_F(ContextImplTest, FrameDeletedBeforeContext) { - chromium::web::FramePtr frame = CreateFrame(); - - // Process the frame creation message. - base::RunLoop().RunUntilIdle(); - - FrameImpl* frame_impl = context_impl()->GetFrameImplForTest(&frame); - WebContentsDeletionObserver deletion_observer( - frame_impl->web_contents_for_test()); - base::RunLoop run_loop; - EXPECT_CALL(deletion_observer, RenderViewDeleted(_)) - .WillOnce(InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); - - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - controller->LoadUrl(url::kAboutBlankURL, nullptr); - - frame.Unbind(); - run_loop.Run(); - - // Check that |context| remains bound after the frame is closed. - EXPECT_TRUE(context()); -} - -IN_PROC_BROWSER_TEST_F(ContextImplTest, ContextDeletedBeforeFrame) { - chromium::web::FramePtr frame = CreateFrame(); - EXPECT_TRUE(frame); - - base::RunLoop run_loop; - frame.set_error_handler([&run_loop]() { run_loop.Quit(); }); - context().Unbind(); - run_loop.Run(); - EXPECT_FALSE(frame); -} - -IN_PROC_BROWSER_TEST_F(ContextImplTest, GoBackAndForward) { - chromium::web::FramePtr frame = CreateFrame(); - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - ASSERT_TRUE(embedded_test_server()->Start()); - GURL title1(embedded_test_server()->GetURL(kPage1Path)); - GURL title2(embedded_test_server()->GetURL(kPage2Path)); - - CheckLoadUrl(title1.spec(), kPage1Title, false, controller.get()); - CheckLoadUrl(title2.spec(), kPage2Title, false, controller.get()); - - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, - MockableOnNavigationStateChanged( - testing::AllOf(Field(&NavigationEvent::title, kPage1Title), - Field(&NavigationEvent::url, IsSet())))) - .WillOnce(InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); - controller->GoBack(); - run_loop.Run(); - navigation_observer_.Acknowledge(); - } - - // At the top of the navigation entry list; this should be a no-op. - controller->GoBack(); - - // Process the navigation request message. - base::RunLoop().RunUntilIdle(); - - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, - MockableOnNavigationStateChanged( - testing::AllOf(Field(&NavigationEvent::title, kPage2Title), - Field(&NavigationEvent::url, IsSet())))) - .WillOnce(InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); - controller->GoForward(); - run_loop.Run(); - navigation_observer_.Acknowledge(); - } - - // At the end of the navigation entry list; this should be a no-op. - controller->GoForward(); - - // Process the navigation request message. - base::RunLoop().RunUntilIdle(); -} - -IN_PROC_BROWSER_TEST_F(ContextImplTest, ReloadFrame) { - chromium::web::FramePtr frame = CreateFrame(); - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - embedded_test_server()->RegisterRequestMonitor(base::BindRepeating( - &ContextImplTest::OnServeHttpRequest, base::Unretained(this))); - - ASSERT_TRUE(embedded_test_server()->Start()); - GURL url(embedded_test_server()->GetURL(kPage1Path)); - - EXPECT_CALL(*this, OnServeHttpRequest(_)); - CheckLoadUrl(url.spec(), kPage1Title, false, controller.get()); - - navigation_observer_.Observe( - context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); - - // Reload with NO_CACHE. - { - base::RunLoop run_loop; - EXPECT_CALL(*this, OnServeHttpRequest(_)); - EXPECT_CALL(navigation_observer_, DidFinishLoad(_, url)) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->Reload(chromium::web::ReloadType::NO_CACHE); - run_loop.Run(); - Mock::VerifyAndClearExpectations(this); - navigation_observer_.Acknowledge(); - } - // Reload with PARTIAL_CACHE. - { - base::RunLoop run_loop; - EXPECT_CALL(*this, OnServeHttpRequest(_)); - EXPECT_CALL(navigation_observer_, DidFinishLoad(_, url)) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->Reload(chromium::web::ReloadType::PARTIAL_CACHE); - run_loop.Run(); - } -} - -IN_PROC_BROWSER_TEST_F(ContextImplTest, GetVisibleEntry) { - chromium::web::FramePtr frame = CreateFrame(); - - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - // Verify that a Frame returns a null NavigationEntry prior to receiving any - // LoadUrl() calls. - { - base::RunLoop run_loop; - controller->GetVisibleEntry( - [&run_loop](std::unique_ptr<chromium::web::NavigationEntry> details) { - EXPECT_EQ(nullptr, details.get()); - run_loop.Quit(); - }); - run_loop.Run(); - } - - ASSERT_TRUE(embedded_test_server()->Start()); - GURL title1(embedded_test_server()->GetURL(kPage1Path)); - GURL title2(embedded_test_server()->GetURL(kPage2Path)); - - // Navigate to a page. - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, - MockableOnNavigationStateChanged( - testing::AllOf(Field(&NavigationEvent::title, kPage1Title), - Field(&NavigationEvent::url, IsSet())))) - .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); - controller->LoadUrl(title1.spec(), nullptr); - run_loop.Run(); - navigation_observer_.Acknowledge(); - } - - // Verify that GetVisibleEntry() reflects the new Frame navigation state. - { - base::RunLoop run_loop; - controller->GetVisibleEntry( - [&run_loop, - &title1](std::unique_ptr<chromium::web::NavigationEntry> details) { - EXPECT_TRUE(details); - EXPECT_EQ(details->url, title1.spec()); - EXPECT_EQ(details->title, kPage1Title); - run_loop.Quit(); - }); - run_loop.Run(); - } - - // Navigate to another page. - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, - MockableOnNavigationStateChanged( - testing::AllOf(Field(&NavigationEvent::title, kPage2Title), - Field(&NavigationEvent::url, IsSet())))) - .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); - controller->LoadUrl(title2.spec(), nullptr); - run_loop.Run(); - navigation_observer_.Acknowledge(); - } - - // Verify the navigation with GetVisibleEntry(). - { - base::RunLoop run_loop; - controller->GetVisibleEntry( - [&run_loop, - &title2](std::unique_ptr<chromium::web::NavigationEntry> details) { - EXPECT_TRUE(details); - EXPECT_EQ(details->url, title2.spec()); - EXPECT_EQ(details->title, kPage2Title); - run_loop.Quit(); - }); - run_loop.Run(); - } - - // Navigate back to the first page. - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, - MockableOnNavigationStateChanged( - testing::AllOf(Field(&NavigationEvent::title, kPage1Title), - Field(&NavigationEvent::url, IsSet())))) - .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); - controller->GoBack(); - run_loop.Run(); - navigation_observer_.Acknowledge(); - } - - // Verify the navigation with GetVisibleEntry(). - { - base::RunLoop run_loop; - controller->GetVisibleEntry( - [&run_loop, - &title1](std::unique_ptr<chromium::web::NavigationEntry> details) { - EXPECT_TRUE(details); - EXPECT_EQ(details->url, title1.spec()); - EXPECT_EQ(details->title, kPage1Title); - run_loop.Quit(); - }); - run_loop.Run(); - } -} - -IN_PROC_BROWSER_TEST_F(ContextImplTest, NoNavigationObserverAttached) { - chromium::web::FramePtr frame; - context()->CreateFrame(frame.NewRequest()); - base::RunLoop().RunUntilIdle(); - - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - ASSERT_TRUE(embedded_test_server()->Start()); - GURL title1(embedded_test_server()->GetURL(kPage1Path)); - GURL title2(embedded_test_server()->GetURL(kPage2Path)); - - navigation_observer_.Observe( - context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); - - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title1)) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->LoadUrl(title1.spec(), nullptr); - run_loop.Run(); - } - - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title2)) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->LoadUrl(title2.spec(), nullptr); - run_loop.Run(); - } -} - -// Verifies that a Frame will handle navigation observer disconnection events -// gracefully. -IN_PROC_BROWSER_TEST_F(ContextImplTest, NavigationObserverDisconnected) { - chromium::web::FramePtr frame = CreateFrame(); - - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - ASSERT_TRUE(embedded_test_server()->Start()); - GURL title1(embedded_test_server()->GetURL(kPage1Path)); - GURL title2(embedded_test_server()->GetURL(kPage2Path)); - - navigation_observer_.Observe( - context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); - - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title1)); - EXPECT_CALL(navigation_observer_, - MockableOnNavigationStateChanged( - testing::AllOf(Field(&NavigationEvent::title, kPage1Title), - Field(&NavigationEvent::url, IsSet())))) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->LoadUrl(title1.spec(), nullptr); - run_loop.Run(); - } - - // Disconnect the observer & spin the runloop to propagate the disconnection - // event over IPC. - navigation_observer_binding_.Unbind(); - base::RunLoop().RunUntilIdle(); - - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title2)) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->LoadUrl(title2.spec(), nullptr); - run_loop.Run(); - } -} - -IN_PROC_BROWSER_TEST_F(ContextImplTest, DISABLED_DelayedNavigationEventAck) { - chromium::web::FramePtr frame = CreateFrame(); - - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - ASSERT_TRUE(embedded_test_server()->Start()); - GURL title1(embedded_test_server()->GetURL(kPage1Path)); - GURL title2(embedded_test_server()->GetURL(kPage2Path)); - - // Expect an navigation event here, but deliberately postpone acknowledgement - // until the end of the test. - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, - MockableOnNavigationStateChanged( - testing::AllOf(Field(&NavigationEvent::title, kPage1Title), - Field(&NavigationEvent::url, IsSet())))) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->LoadUrl(title1.spec(), nullptr); - run_loop.Run(); - Mock::VerifyAndClearExpectations(this); - } - - // Since we have blocked NavigationEventObserver's flow, we must observe the - // WebContents events directly via a test-only seam. - navigation_observer_.Observe( - context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); - - // Navigate to a second page. - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title2)) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->LoadUrl(title2.spec(), nullptr); - run_loop.Run(); - Mock::VerifyAndClearExpectations(this); - } - - // Navigate to the first page. - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title1)) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->LoadUrl(title1.spec(), nullptr); - run_loop.Run(); - Mock::VerifyAndClearExpectations(this); - } - - // Since there was no observable change in navigation state since the last - // ack, there should be no more NavigationEvents generated. - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, - MockableOnNavigationStateChanged( - testing::AllOf(Field(&NavigationEvent::title, kPage1Title), - Field(&NavigationEvent::url, IsSet())))) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - navigation_observer_.Acknowledge(); - run_loop.Run(); - } -} - -// Observes events specific to the Stop() test case. -struct WebContentsObserverForStop : public content::WebContentsObserver { - using content::WebContentsObserver::Observe; - MOCK_METHOD1(DidStartNavigation, void(content::NavigationHandle*)); - MOCK_METHOD0(NavigationStopped, void()); -}; - -IN_PROC_BROWSER_TEST_F(ContextImplTest, Stop) { - chromium::web::FramePtr frame = CreateFrame(); - - chromium::web::NavigationControllerPtr controller; - frame->GetNavigationController(controller.NewRequest()); - - ASSERT_TRUE(embedded_test_server()->Start()); - - // Use a request handler that will accept the connection and stall - // indefinitely. - GURL hung_url(embedded_test_server()->GetURL("/hung")); - - WebContentsObserverForStop observer; - observer.Observe( - context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); - - { - base::RunLoop run_loop; - EXPECT_CALL(observer, DidStartNavigation(_)) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->LoadUrl(hung_url.spec(), nullptr); - run_loop.Run(); - Mock::VerifyAndClearExpectations(this); - } - - EXPECT_TRUE( - context_impl()->GetFrameImplForTest(&frame)->web_contents_->IsLoading()); - - { - base::RunLoop run_loop; - EXPECT_CALL(observer, NavigationStopped()) - .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); - controller->Stop(); - run_loop.Run(); - Mock::VerifyAndClearExpectations(this); - } - - EXPECT_FALSE( - context_impl()->GetFrameImplForTest(&frame)->web_contents_->IsLoading()); -} - void OnCookiesReceived(net::CookieList* output, base::OnceClosure on_received_cb, const net::CookieList& cookies) { @@ -701,8 +154,13 @@ chromium::web::NavigationControllerPtr controller; frame->GetNavigationController(controller.NewRequest()); - CheckLoadUrl(url::kAboutBlankURL, url::kAboutBlankURL, false, - controller.get()); + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, + MockableOnNavigationStateChanged( + Field(&NavigationDetails::url, url::kAboutBlankURL))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->LoadUrl(url::kAboutBlankURL, nullptr); + run_loop.Run(); frame.Unbind(); } @@ -715,14 +173,12 @@ chromium::web::NavigationControllerPtr nav; frame->GetNavigationController(nav.NewRequest()); - { - base::RunLoop run_loop; - EXPECT_CALL(navigation_observer_, MockableOnNavigationStateChanged(_)) - .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, MockableOnNavigationStateChanged(_)) + .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); - nav->LoadUrl(cookie_url.spec(), nullptr); - run_loop.Run(); - } + nav->LoadUrl(cookie_url.spec(), nullptr); + run_loop.Run(); auto cookies = GetCookies(); bool found = false;
diff --git a/webrunner/browser/frame_impl.cc b/webrunner/browser/frame_impl.cc index ecf931ed..f7c21a9 100644 --- a/webrunner/browser/frame_impl.cc +++ b/webrunner/browser/frame_impl.cc
@@ -17,6 +17,7 @@ #include "ui/aura/window.h" #include "ui/aura/window_tree_host_platform.h" #include "ui/platform_window/platform_window_init_properties.h" +#include "ui/wm/core/base_focus_rules.h" #include "url/gurl.h" #include "webrunner/browser/context_impl.h" @@ -100,13 +101,32 @@ return is_changed; } +class FrameFocusRules : public wm::BaseFocusRules { + public: + FrameFocusRules() = default; + ~FrameFocusRules() override = default; + + // wm::BaseFocusRules implementation. + bool SupportsChildActivation(aura::Window*) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(FrameFocusRules); +}; + +bool FrameFocusRules::SupportsChildActivation(aura::Window*) const { + // TODO(crbug.com/878439): Return a result based on window properties such as + // visibility. + return true; +} + } // namespace FrameImpl::FrameImpl(std::unique_ptr<content::WebContents> web_contents, ContextImpl* context, fidl::InterfaceRequest<chromium::web::Frame> frame_request) : web_contents_(std::move(web_contents)), - focus_controller_(std::make_unique<wm::FocusController>(this)), + focus_controller_( + std::make_unique<wm::FocusController>(new FrameFocusRules)), context_(context), binding_(this, std::move(frame_request)) { web_contents_->SetDelegate(this); @@ -117,7 +137,7 @@ if (window_tree_host_) { aura::client::SetFocusClient(root_window(), nullptr); wm::SetActivationClient(root_window(), nullptr); - + web_contents_->ClosePage(); window_tree_host_->Hide(); window_tree_host_->compositor()->SetVisible(false); @@ -301,10 +321,4 @@ } } -bool FrameImpl::SupportsChildActivation(aura::Window*) const { - // TODO(crbug.com/878439): Return a result based on window properties such as - // visibility. - return true; -} - } // namespace webrunner
diff --git a/webrunner/browser/frame_impl.h b/webrunner/browser/frame_impl.h index 0a81e6e9..959dc69 100644 --- a/webrunner/browser/frame_impl.h +++ b/webrunner/browser/frame_impl.h
@@ -15,7 +15,6 @@ #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" #include "ui/aura/window_tree_host.h" -#include "ui/wm/core/base_focus_rules.h" #include "ui/wm/core/focus_controller.h" #include "url/gurl.h" #include "webrunner/fidl/chromium/web/cpp/fidl.h" @@ -37,8 +36,7 @@ class FrameImpl : public chromium::web::Frame, public chromium::web::NavigationController, public content::WebContentsObserver, - public content::WebContentsDelegate, - public wm::BaseFocusRules { + public content::WebContentsDelegate { public: FrameImpl(std::unique_ptr<content::WebContents> web_contents, ContextImpl* context, @@ -70,11 +68,11 @@ override; private: - FRIEND_TEST_ALL_PREFIXES(ContextImplTest, DelayedNavigationEventAck); - FRIEND_TEST_ALL_PREFIXES(ContextImplTest, NavigationObserverDisconnected); - FRIEND_TEST_ALL_PREFIXES(ContextImplTest, NoNavigationObserverAttached); - FRIEND_TEST_ALL_PREFIXES(ContextImplTest, ReloadFrame); - FRIEND_TEST_ALL_PREFIXES(ContextImplTest, Stop); + FRIEND_TEST_ALL_PREFIXES(FrameImplTest, DelayedNavigationEventAck); + FRIEND_TEST_ALL_PREFIXES(FrameImplTest, NavigationObserverDisconnected); + FRIEND_TEST_ALL_PREFIXES(FrameImplTest, NoNavigationObserverAttached); + FRIEND_TEST_ALL_PREFIXES(FrameImplTest, ReloadFrame); + FRIEND_TEST_ALL_PREFIXES(FrameImplTest, Stop); aura::Window* root_window() const { return window_tree_host_->window(); } @@ -101,9 +99,6 @@ void DidFinishLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url) override; - // wm::BaseFocusRules implementation. - bool SupportsChildActivation(aura::Window*) const override; - std::unique_ptr<aura::WindowTreeHost> window_tree_host_; std::unique_ptr<content::WebContents> web_contents_; std::unique_ptr<wm::FocusController> focus_controller_;
diff --git a/webrunner/browser/frame_impl_browsertest.cc b/webrunner/browser/frame_impl_browsertest.cc new file mode 100644 index 0000000..c4426ae --- /dev/null +++ b/webrunner/browser/frame_impl_browsertest.cc
@@ -0,0 +1,527 @@ +// 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 <lib/fidl/cpp/binding.h> + +#include "base/macros.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/url_request/url_request_context.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/url_constants.h" +#include "webrunner/browser/frame_impl.h" +#include "webrunner/browser/test_common.h" +#include "webrunner/browser/webrunner_browser_test.h" +#include "webrunner/service/common.h" + +namespace webrunner { + +using testing::_; +using testing::AllOf; +using testing::Field; +using testing::InvokeWithoutArgs; +using testing::Mock; + +// Use a shorter name for NavigationEvent, because it is +// referenced frequently in this file. +using NavigationDetails = chromium::web::NavigationEvent; + +const char kPage1Path[] = "/title1.html"; +const char kPage2Path[] = "/title2.html"; +const char kPage1Title[] = "title 1"; +const char kPage2Title[] = "title 2"; +const char kDataUrl[] = + "data:text/html;base64,PGI+SGVsbG8sIHdvcmxkLi4uPC9iPg=="; + +MATCHER(IsSet, "Checks if an optional field is set.") { + return !arg.is_null(); +} + +// Defines a suite of tests that exercise Frame-level functionality, such as +// navigation commands and page events. +class FrameImplTest : public WebRunnerBrowserTest { + public: + FrameImplTest() = default; + ~FrameImplTest() = default; + + MOCK_METHOD1(OnServeHttpRequest, + void(const net::test_server::HttpRequest& request)); + + protected: + // Creates a Frame with |navigation_observer_| attached. + chromium::web::FramePtr CreateFrame() { + return WebRunnerBrowserTest::CreateFrame(&navigation_observer_); + } + + // Navigates a |controller| to |url|, blocking until navigation is complete. + void CheckLoadUrl(const std::string& url, + const std::string& expected_title, + chromium::web::NavigationController* controller) { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, + MockableOnNavigationStateChanged(testing::AllOf( + Field(&NavigationDetails::title, expected_title), + Field(&NavigationDetails::url, url)))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->LoadUrl(url, nullptr); + run_loop.Run(); + Mock::VerifyAndClearExpectations(this); + navigation_observer_.Acknowledge(); + } + + testing::StrictMock<MockNavigationObserver> navigation_observer_; + + private: + DISALLOW_COPY_AND_ASSIGN(FrameImplTest); +}; + +class WebContentsDeletionObserver : public content::WebContentsObserver { + public: + explicit WebContentsDeletionObserver(content::WebContents* web_contents) + : content::WebContentsObserver(web_contents) {} + + MOCK_METHOD1(RenderViewDeleted, + void(content::RenderViewHost* render_view_host)); +}; + +// Verifies that the browser will navigate and generate a navigation observer +// event when LoadUrl() is called. +IN_PROC_BROWSER_TEST_F(FrameImplTest, NavigateFrame) { + chromium::web::FramePtr frame = CreateFrame(); + + chromium::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + CheckLoadUrl(url::kAboutBlankURL, url::kAboutBlankURL, controller.get()); + + frame.Unbind(); +} + +IN_PROC_BROWSER_TEST_F(FrameImplTest, NavigateDataFrame) { + chromium::web::FramePtr frame = CreateFrame(); + + chromium::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + CheckLoadUrl(kDataUrl, kDataUrl, controller.get()); + + frame.Unbind(); +} + +IN_PROC_BROWSER_TEST_F(FrameImplTest, FrameDeletedBeforeContext) { + chromium::web::FramePtr frame = CreateFrame(); + + // Process the frame creation message. + base::RunLoop().RunUntilIdle(); + + FrameImpl* frame_impl = context_impl()->GetFrameImplForTest(&frame); + WebContentsDeletionObserver deletion_observer( + frame_impl->web_contents_for_test()); + base::RunLoop run_loop; + EXPECT_CALL(deletion_observer, RenderViewDeleted(_)) + .WillOnce(InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); + + chromium::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + controller->LoadUrl(url::kAboutBlankURL, nullptr); + + frame.Unbind(); + run_loop.Run(); + + // Check that |context| remains bound after the frame is closed. + EXPECT_TRUE(context()); +} + +IN_PROC_BROWSER_TEST_F(FrameImplTest, ContextDeletedBeforeFrame) { + chromium::web::FramePtr frame = CreateFrame(); + EXPECT_TRUE(frame); + + base::RunLoop run_loop; + frame.set_error_handler([&run_loop]() { run_loop.Quit(); }); + context().Unbind(); + run_loop.Run(); + EXPECT_FALSE(frame); +} + +IN_PROC_BROWSER_TEST_F(FrameImplTest, GoBackAndForward) { + chromium::web::FramePtr frame = CreateFrame(); + chromium::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL title1(embedded_test_server()->GetURL(kPage1Path)); + GURL title2(embedded_test_server()->GetURL(kPage2Path)); + + CheckLoadUrl(title1.spec(), kPage1Title, controller.get()); + CheckLoadUrl(title2.spec(), kPage2Title, controller.get()); + + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, + MockableOnNavigationStateChanged(testing::AllOf( + Field(&NavigationDetails::title, kPage1Title), + Field(&NavigationDetails::url, IsSet())))) + .WillOnce(InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); + controller->GoBack(); + run_loop.Run(); + navigation_observer_.Acknowledge(); + } + + // At the top of the navigation entry list; this should be a no-op. + controller->GoBack(); + + // Process the navigation request message. + base::RunLoop().RunUntilIdle(); + + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, + MockableOnNavigationStateChanged(testing::AllOf( + Field(&NavigationDetails::title, kPage2Title), + Field(&NavigationDetails::url, IsSet())))) + .WillOnce(InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); + controller->GoForward(); + run_loop.Run(); + navigation_observer_.Acknowledge(); + } + + // At the end of the navigation entry list; this should be a no-op. + controller->GoForward(); + + // Process the navigation request message. + base::RunLoop().RunUntilIdle(); +} + +IN_PROC_BROWSER_TEST_F(FrameImplTest, ReloadFrame) { + chromium::web::FramePtr frame = CreateFrame(); + chromium::web::NavigationControllerPtr navigation_controller; + frame->GetNavigationController(navigation_controller.NewRequest()); + + embedded_test_server()->RegisterRequestMonitor(base::BindRepeating( + &FrameImplTest::OnServeHttpRequest, base::Unretained(this))); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url(embedded_test_server()->GetURL(kPage1Path)); + + EXPECT_CALL(*this, OnServeHttpRequest(_)); + CheckLoadUrl(url.spec(), kPage1Title, navigation_controller.get()); + + navigation_observer_.Observe( + context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); + + // Reload with NO_CACHE. + { + base::RunLoop run_loop; + EXPECT_CALL(*this, OnServeHttpRequest(_)); + EXPECT_CALL(navigation_observer_, DidFinishLoad(_, url)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + navigation_controller->Reload(chromium::web::ReloadType::NO_CACHE); + run_loop.Run(); + Mock::VerifyAndClearExpectations(this); + navigation_observer_.Acknowledge(); + } + // Reload with PARTIAL_CACHE. + { + base::RunLoop run_loop; + EXPECT_CALL(*this, OnServeHttpRequest(_)); + EXPECT_CALL(navigation_observer_, DidFinishLoad(_, url)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + navigation_controller->Reload(chromium::web::ReloadType::PARTIAL_CACHE); + run_loop.Run(); + } +} + +IN_PROC_BROWSER_TEST_F(FrameImplTest, GetVisibleEntry) { + chromium::web::FramePtr frame = CreateFrame(); + + chromium::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + // Verify that a Frame returns a null NavigationEntry prior to receiving any + // LoadUrl() calls. + { + base::RunLoop run_loop; + controller->GetVisibleEntry( + [&run_loop](std::unique_ptr<chromium::web::NavigationEntry> details) { + EXPECT_EQ(nullptr, details.get()); + run_loop.Quit(); + }); + run_loop.Run(); + } + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL title1(embedded_test_server()->GetURL(kPage1Path)); + GURL title2(embedded_test_server()->GetURL(kPage2Path)); + + // Navigate to a page. + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, + MockableOnNavigationStateChanged(testing::AllOf( + Field(&NavigationDetails::title, kPage1Title), + Field(&NavigationDetails::url, IsSet())))) + .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); + controller->LoadUrl(title1.spec(), nullptr); + run_loop.Run(); + navigation_observer_.Acknowledge(); + } + + // Verify that GetVisibleEntry() reflects the new Frame navigation state. + { + base::RunLoop run_loop; + controller->GetVisibleEntry( + [&run_loop, + &title1](std::unique_ptr<chromium::web::NavigationEntry> details) { + EXPECT_TRUE(details); + EXPECT_EQ(details->url, title1.spec()); + EXPECT_EQ(details->title, kPage1Title); + run_loop.Quit(); + }); + run_loop.Run(); + } + + // Navigate to another page. + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, + MockableOnNavigationStateChanged(testing::AllOf( + Field(&NavigationDetails::title, kPage2Title), + Field(&NavigationDetails::url, IsSet())))) + .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); + controller->LoadUrl(title2.spec(), nullptr); + run_loop.Run(); + navigation_observer_.Acknowledge(); + } + + // Verify the navigation with GetVisibleEntry(). + { + base::RunLoop run_loop; + controller->GetVisibleEntry( + [&run_loop, + &title2](std::unique_ptr<chromium::web::NavigationEntry> details) { + EXPECT_TRUE(details); + EXPECT_EQ(details->url, title2.spec()); + EXPECT_EQ(details->title, kPage2Title); + run_loop.Quit(); + }); + run_loop.Run(); + } + + // Navigate back to the first page. + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, + MockableOnNavigationStateChanged(testing::AllOf( + Field(&NavigationDetails::title, kPage1Title), + Field(&NavigationDetails::url, IsSet())))) + .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); + controller->GoBack(); + run_loop.Run(); + navigation_observer_.Acknowledge(); + } + + // Verify the navigation with GetVisibleEntry(). + { + base::RunLoop run_loop; + controller->GetVisibleEntry( + [&run_loop, + &title1](std::unique_ptr<chromium::web::NavigationEntry> details) { + EXPECT_TRUE(details); + EXPECT_EQ(details->url, title1.spec()); + EXPECT_EQ(details->title, kPage1Title); + run_loop.Quit(); + }); + run_loop.Run(); + } +} + +IN_PROC_BROWSER_TEST_F(FrameImplTest, NoNavigationObserverAttached) { + chromium::web::FramePtr frame; + context()->CreateFrame(frame.NewRequest()); + base::RunLoop().RunUntilIdle(); + + chromium::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL title1(embedded_test_server()->GetURL(kPage1Path)); + GURL title2(embedded_test_server()->GetURL(kPage2Path)); + + navigation_observer_.Observe( + context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); + + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title1)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->LoadUrl(title1.spec(), nullptr); + run_loop.Run(); + } + + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title2)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->LoadUrl(title2.spec(), nullptr); + run_loop.Run(); + } +} + +// Verifies that a Frame will handle navigation observer disconnection events +// gracefully. +IN_PROC_BROWSER_TEST_F(FrameImplTest, NavigationObserverDisconnected) { + chromium::web::FramePtr frame = CreateFrame(); + + chromium::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL title1(embedded_test_server()->GetURL(kPage1Path)); + GURL title2(embedded_test_server()->GetURL(kPage2Path)); + + navigation_observer_.Observe( + context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); + + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title1)); + EXPECT_CALL(navigation_observer_, + MockableOnNavigationStateChanged(testing::AllOf( + Field(&NavigationDetails::title, kPage1Title), + Field(&NavigationDetails::url, IsSet())))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->LoadUrl(title1.spec(), nullptr); + run_loop.Run(); + } + + // Disconnect the observer & spin the runloop to propagate the disconnection + // event over IPC. + navigation_observer_bindings().CloseAll(); + base::RunLoop().RunUntilIdle(); + + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title2)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->LoadUrl(title2.spec(), nullptr); + run_loop.Run(); + } +} + +IN_PROC_BROWSER_TEST_F(FrameImplTest, DISABLED_DelayedNavigationEventAck) { + chromium::web::FramePtr frame = CreateFrame(); + + chromium::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL title1(embedded_test_server()->GetURL(kPage1Path)); + GURL title2(embedded_test_server()->GetURL(kPage2Path)); + + // Expect an navigation event here, but deliberately postpone acknowledgement + // until the end of the test. + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, + MockableOnNavigationStateChanged(testing::AllOf( + Field(&NavigationDetails::title, kPage1Title), + Field(&NavigationDetails::url, IsSet())))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->LoadUrl(title1.spec(), nullptr); + run_loop.Run(); + Mock::VerifyAndClearExpectations(this); + } + + // Since we have blocked NavigationEventObserver's flow, we must observe the + // WebContents events directly via a test-only seam. + navigation_observer_.Observe( + context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); + + // Navigate to a second page. + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title2)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->LoadUrl(title2.spec(), nullptr); + run_loop.Run(); + Mock::VerifyAndClearExpectations(this); + } + + // Navigate to the first page. + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title1)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->LoadUrl(title1.spec(), nullptr); + run_loop.Run(); + Mock::VerifyAndClearExpectations(this); + } + + // Since there was no observable change in navigation state since the last + // ack, there should be no more NavigationEvents generated. + { + base::RunLoop run_loop; + EXPECT_CALL(navigation_observer_, + MockableOnNavigationStateChanged(testing::AllOf( + Field(&NavigationDetails::title, kPage1Title), + Field(&NavigationDetails::url, IsSet())))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + navigation_observer_.Acknowledge(); + run_loop.Run(); + } +} + +// Observes events specific to the Stop() test case. +struct WebContentsObserverForStop : public content::WebContentsObserver { + using content::WebContentsObserver::Observe; + MOCK_METHOD1(DidStartNavigation, void(content::NavigationHandle*)); + MOCK_METHOD0(NavigationStopped, void()); +}; + +IN_PROC_BROWSER_TEST_F(FrameImplTest, Stop) { + chromium::web::FramePtr frame = CreateFrame(); + + chromium::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + + ASSERT_TRUE(embedded_test_server()->Start()); + + // Use a request handler that will accept the connection and stall + // indefinitely. + GURL hung_url(embedded_test_server()->GetURL("/hung")); + + WebContentsObserverForStop observer; + observer.Observe( + context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); + + { + base::RunLoop run_loop; + EXPECT_CALL(observer, DidStartNavigation(_)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->LoadUrl(hung_url.spec(), nullptr); + run_loop.Run(); + Mock::VerifyAndClearExpectations(this); + } + + EXPECT_TRUE( + context_impl()->GetFrameImplForTest(&frame)->web_contents_->IsLoading()); + + { + base::RunLoop run_loop; + EXPECT_CALL(observer, NavigationStopped()) + .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); + controller->Stop(); + run_loop.Run(); + Mock::VerifyAndClearExpectations(this); + } + + EXPECT_FALSE( + context_impl()->GetFrameImplForTest(&frame)->web_contents_->IsLoading()); +} + +} // namespace webrunner
diff --git a/webrunner/browser/test_common.cc b/webrunner/browser/test_common.cc new file mode 100644 index 0000000..3365aa2 --- /dev/null +++ b/webrunner/browser/test_common.cc
@@ -0,0 +1,32 @@ +// 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 "webrunner/browser/test_common.h" + +#include <utility> + +#include "base/run_loop.h" + +namespace webrunner { + +MockNavigationObserver::MockNavigationObserver() = default; + +MockNavigationObserver::~MockNavigationObserver() = default; + +void MockNavigationObserver::Acknowledge() { + DCHECK(navigation_ack_callback_); + std::move(navigation_ack_callback_)(); + + // Pump the acknowledgement message over IPC. + base::RunLoop().RunUntilIdle(); +} + +void MockNavigationObserver::OnNavigationStateChanged( + chromium::web::NavigationEvent change, + OnNavigationStateChangedCallback callback) { + MockableOnNavigationStateChanged(std::move(change)); + navigation_ack_callback_ = std::move(callback); +} + +} // namespace webrunner
diff --git a/webrunner/browser/test_common.h b/webrunner/browser/test_common.h new file mode 100644 index 0000000..b150e85 --- /dev/null +++ b/webrunner/browser/test_common.h
@@ -0,0 +1,50 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBRUNNER_BROWSER_TEST_COMMON_H_ +#define WEBRUNNER_BROWSER_TEST_COMMON_H_ + +#include "content/public/browser/web_contents_observer.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "webrunner/fidl/chromium/web/cpp/fidl.h" + +namespace webrunner { + +// Defines mock methods used by tests to observe NavigationStateChangeEvents +// and lower-level WebContentsObserver events. +class MockNavigationObserver : public chromium::web::NavigationEventObserver, + public content::WebContentsObserver { + public: + using content::WebContentsObserver::Observe; + + MockNavigationObserver(); + ~MockNavigationObserver() override; + + // Acknowledges processing of the most recent OnNavigationStateChanged call. + void Acknowledge(); + + MOCK_METHOD1(MockableOnNavigationStateChanged, + void(chromium::web::NavigationEvent change)); + + // chromium::web::NavigationEventObserver implementation. + // Proxies calls to MockableOnNavigationStateChanged(), because GMock does + // not work well with fit::Callbacks inside mocked actions. + void OnNavigationStateChanged( + chromium::web::NavigationEvent change, + OnNavigationStateChangedCallback callback) override; + + // WebContentsObserver implementation. + MOCK_METHOD2(DidFinishLoad, + void(content::RenderFrameHost* render_frame_host, + const GURL& validated_url)); + + private: + OnNavigationStateChangedCallback navigation_ack_callback_; + + DISALLOW_COPY_AND_ASSIGN(MockNavigationObserver); +}; + +} // namespace webrunner + +#endif // WEBRUNNER_BROWSER_TEST_COMMON_H_
diff --git a/webrunner/browser/webrunner_browser_test.cc b/webrunner/browser/webrunner_browser_test.cc index 75c59e2..d541303 100644 --- a/webrunner/browser/webrunner_browser_test.cc +++ b/webrunner/browser/webrunner_browser_test.cc
@@ -37,6 +37,29 @@ context_.Unbind(); } +void WebRunnerBrowserTest::TearDownOnMainThread() { + navigation_observer_bindings_.CloseAll(); +} + +chromium::web::FramePtr WebRunnerBrowserTest::CreateFrame( + chromium::web::NavigationEventObserver* observer) { + chromium::web::FramePtr frame; + context_->CreateFrame(frame.NewRequest()); + + if (observer) { + fidl::InterfaceRequest<chromium::web::NavigationEventObserver> + observer_request; + frame->SetNavigationEventObserver( + navigation_observer_bindings_.AddBinding(observer)); + } + + // Pump the messages so that the caller can use the Frame instance + // immediately after this function returns. + base::RunLoop().RunUntilIdle(); + + return frame; +} + // static void WebRunnerBrowserTest::SetContextClientChannel(zx::channel channel) { DCHECK(channel);
diff --git a/webrunner/browser/webrunner_browser_test.h b/webrunner/browser/webrunner_browser_test.h index a47bd23..7bd5f33 100644 --- a/webrunner/browser/webrunner_browser_test.h +++ b/webrunner/browser/webrunner_browser_test.h
@@ -5,6 +5,7 @@ #ifndef WEBRUNNER_BROWSER_WEBRUNNER_BROWSER_TEST_H_ #define WEBRUNNER_BROWSER_WEBRUNNER_BROWSER_TEST_H_ +#include <lib/fidl/cpp/binding_set.h> #include <memory> #include "base/macros.h" @@ -26,18 +27,31 @@ // object by WebRunnerBrowserTest. static void SetContextClientChannel(zx::channel channel); + // Creates a Frame for this Context. + // |observer|: If set, specifies the navigation observer for the Frame. + chromium::web::FramePtr CreateFrame( + chromium::web::NavigationEventObserver* observer); + // Gets the client object for the Context service. chromium::web::ContextPtr& context() { return context_; } // Gets the underlying ContextImpl service instance. ContextImpl* context_impl() const; + fidl::BindingSet<chromium::web::NavigationEventObserver>& + navigation_observer_bindings() { + return navigation_observer_bindings_; + } + // content::BrowserTestBase implementation. void PreRunTestOnMainThread() override; void PostRunTestOnMainThread() override; + void TearDownOnMainThread() override; private: chromium::web::ContextPtr context_; + fidl::BindingSet<chromium::web::NavigationEventObserver> + navigation_observer_bindings_; DISALLOW_COPY_AND_ASSIGN(WebRunnerBrowserTest); };