diff --git a/DEPS b/DEPS index f992d43..ca8321f 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': 'c062b6be5a01b3f4845c64181b1588d03c02d1e1', + 'skia_revision': 'b284280be4cc15bd13bc8c53b9f486d027fcc939', # 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': '58ea46ee6c757b368c2e719085a909394225fe11', + 'v8_revision': 'd729403cd1d7b25f51637aa900527903b8837ced', # 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. @@ -117,7 +117,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '096c5296c3b0bd2c83211b256d28fe3288792eac', + 'angle_revision': '2160821e16dbc4f2715422940df914ed5e77bf92', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -539,7 +539,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '09f0990a2db0cf45d076a0c6d99a88853b258a10', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'cb29fbd231d64bbc5d23bbf04fb47637111b71bb', 'condition': 'checkout_linux', }, @@ -1034,7 +1034,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '21dbf06b5aa6c7dc8cf56314d4a3f96f57956c53', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '715cc238d24b5d9bb7a7619946a8bf9fe44d339e', + Var('webrtc_git') + '/src.git' + '@' + 'e71d1bb7fc22c7a08f34391b69c722d07c2100f2', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/browser/net/aw_cookie_change_dispatcher_wrapper.cc b/android_webview/browser/net/aw_cookie_change_dispatcher_wrapper.cc index fc0813b..de3ea504 100644 --- a/android_webview/browser/net/aw_cookie_change_dispatcher_wrapper.cc +++ b/android_webview/browser/net/aw_cookie_change_dispatcher_wrapper.cc
@@ -49,7 +49,7 @@ DCHECK(callback_list_.empty()); nested_subscription_ = - new NestedSubscription(url, name, weak_factory_.GetWeakPtr()); + NestedSubscription::Create(url, name, weak_factory_.GetWeakPtr()); return std::make_unique<AwCookieChangeSubscription>( callback_list_.Add(std::move(callback))); } @@ -61,21 +61,28 @@ class NestedSubscription : public base::RefCountedDeleteOnSequence<NestedSubscription> { public: - NestedSubscription(const GURL& url, - const std::string& name, - base::WeakPtr<SubscriptionWrapper> subscription_wrapper) - : base::RefCountedDeleteOnSequence<NestedSubscription>( - GetCookieStoreTaskRunner()), - subscription_wrapper_(subscription_wrapper), - client_task_runner_(base::ThreadTaskRunnerHandle::Get()) { - PostTaskToCookieStoreTaskRunner( - base::BindOnce(&NestedSubscription::Subscribe, this, url, name)); + static scoped_refptr<NestedSubscription> Create( + const GURL& url, + const std::string& name, + base::WeakPtr<SubscriptionWrapper> subscription_wrapper) { + auto subscription = base::WrapRefCounted( + new NestedSubscription(std::move(subscription_wrapper))); + PostTaskToCookieStoreTaskRunner(base::BindOnce( + &NestedSubscription::Subscribe, subscription, url, name)); + return subscription; } private: friend class base::RefCountedDeleteOnSequence<NestedSubscription>; friend class base::DeleteHelper<NestedSubscription>; + explicit NestedSubscription( + base::WeakPtr<SubscriptionWrapper> subscription_wrapper) + : base::RefCountedDeleteOnSequence<NestedSubscription>( + GetCookieStoreTaskRunner()), + subscription_wrapper_(subscription_wrapper), + client_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} + ~NestedSubscription() {} void Subscribe(const GURL& url, const std::string& name) {
diff --git a/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh b/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh index 74feb16..5563630 100755 --- a/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh +++ b/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh
@@ -10,7 +10,7 @@ # needs to be installed on the device (e.g. system_webview_apk). # 2. Build system_webview_shell_layout_test_apk. This will also # create a base script for running tests used here. -# 3. Execute run_test_rebaseline.sh [builddir] +# 3. Execute run_tests_rebaseline.sh [builddir] # "builddir" is the build output directory (e.g. out/Debug/ # which is also the default if no directory is provided). # This script will produce a shadow test_rebaseline/ directory @@ -42,7 +42,7 @@ adb shell am instrument -w -e mode rebaseline -e class \ $PACKAGE_NAME.WebViewLayoutTest \ - $PACKAGE_NAME/$PACKAGE_NAME.WebViewLayoutTestRunner + $PACKAGE_NAME/android.support.test.runner.AndroidJUnitRunner adb pull $DEVICE_WEBVIEW_TEST_PATH ../test_rebaseline/ exit 0
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 3bd5127f..4d18a7bc 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -278,8 +278,6 @@ "frame/default_frame_header.h", "frame/detached_title_area_renderer.cc", "frame/detached_title_area_renderer.h", - "frame/frame_border_hit_test.cc", - "frame/frame_border_hit_test.h", "frame/frame_header.cc", "frame/frame_header.h", "frame/frame_header_util.cc", @@ -739,8 +737,6 @@ "system/network/vpn_list_view.h", "system/network/wifi_toggle_notification_controller.cc", "system/network/wifi_toggle_notification_controller.h", - "system/networking_config_delegate.cc", - "system/networking_config_delegate.h", "system/night_light/night_light_controller.cc", "system/night_light/night_light_controller.h", "system/night_light/night_light_feature_pod_controller.cc",
diff --git a/ash/frame/caption_buttons/frame_back_button.cc b/ash/frame/caption_buttons/frame_back_button.cc index c772dc4..0bae36ce5 100644 --- a/ash/frame/caption_buttons/frame_back_button.cc +++ b/ash/frame/caption_buttons/frame_back_button.cc
@@ -10,6 +10,7 @@ #include "ash/strings/grit/ash_strings.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" +#include "ui/base/hit_test.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/events/event_sink.h" @@ -18,7 +19,7 @@ namespace ash { FrameBackButton::FrameBackButton() - : FrameCaptionButton(this, CAPTION_BUTTON_ICON_BACK) { + : FrameCaptionButton(this, CAPTION_BUTTON_ICON_BACK, HTMENU) { SetPreferredSize(GetAshLayoutSize(AshLayoutSize::kNonBrowserCaption)); SetAccessibleName( l10n_util::GetStringUTF16(IDS_ASH_WINDOW_CONTROL_ACCNAME_BACK));
diff --git a/ash/frame/caption_buttons/frame_caption_button.cc b/ash/frame/caption_buttons/frame_caption_button.cc index 40d4d264..4942d2e4 100644 --- a/ash/frame/caption_buttons/frame_caption_button.cc +++ b/ash/frame/caption_buttons/frame_caption_button.cc
@@ -5,6 +5,7 @@ #include "ash/frame/caption_buttons/frame_caption_button.h" #include "ash/public/cpp/ash_constants.h" +#include "ui/base/hit_test.h" #include "ui/gfx/animation/slide_animation.h" #include "ui/gfx/animation/throb_animation.h" #include "ui/gfx/canvas.h" @@ -16,6 +17,7 @@ #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_mask.h" #include "ui/views/animation/ink_drop_ripple.h" +#include "ui/views/view_properties.h" namespace ash { @@ -68,7 +70,8 @@ const char FrameCaptionButton::kViewClassName[] = "FrameCaptionButton"; FrameCaptionButton::FrameCaptionButton(views::ButtonListener* listener, - CaptionButtonIcon icon) + CaptionButtonIcon icon, + int hit_test_type) : Button(listener), icon_(icon), background_color_(SK_ColorWHITE), @@ -76,6 +79,8 @@ paint_as_active_(false), alpha_(255), swap_images_animation_(new gfx::SlideAnimation(this)) { + SetProperty(views::kHitTestComponentKey, hit_test_type); + set_animate_on_state_change(true); swap_images_animation_->Reset(1);
diff --git a/ash/frame/caption_buttons/frame_caption_button.h b/ash/frame/caption_buttons/frame_caption_button.h index 99ad84d2..9dee774 100644 --- a/ash/frame/caption_buttons/frame_caption_button.h +++ b/ash/frame/caption_buttons/frame_caption_button.h
@@ -33,7 +33,9 @@ static const char kViewClassName[]; - FrameCaptionButton(views::ButtonListener* listener, CaptionButtonIcon icon); + FrameCaptionButton(views::ButtonListener* listener, + CaptionButtonIcon icon, + int hit_test_type); ~FrameCaptionButton() override; // Gets the color to use for a frame caption button while a theme color is
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view.cc b/ash/frame/caption_buttons/frame_caption_button_container_view.cc index 86424a1..8767920 100644 --- a/ash/frame/caption_buttons/frame_caption_button_container_view.cc +++ b/ash/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -94,15 +94,6 @@ static_cast<float>(kHidePositionDelayMs) / kHideAnimationDurationMs; } -// Converts |point| from |src| to |dst| and hittests against |dst|. -bool ConvertPointToViewAndHitTest(const views::View* src, - const views::View* dst, - const gfx::Point& point) { - gfx::Point converted(point); - views::View::ConvertPointToTarget(src, dst, &converted); - return dst->HitTestPoint(converted); -} - // Bounds animation values to the range 0.0 - 1.0. Allows for mapping of offset // animations to the expected range so that gfx::Tween::CalculateValue() can be // used. @@ -199,12 +190,13 @@ } // Insert the buttons left to right. - menu_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MENU); + menu_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MENU, HTMENU); menu_button_->SetAccessibleName( l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MENU)); AddChildView(menu_button_); - minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE); + minimize_button_ = + new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE, HTMINBUTTON); minimize_button_->SetAccessibleName( l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE)); AddChildView(minimize_button_); @@ -214,7 +206,8 @@ l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE)); AddChildView(size_button_); - close_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE); + close_button_ = + new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE, HTCLOSE); close_button_->SetAccessibleName( l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); AddChildView(close_button_); @@ -269,24 +262,6 @@ SetButtonsToNormal(ANIMATE_NO); } -int FrameCaptionButtonContainerView::NonClientHitTest( - const gfx::Point& point) const { - if (close_button_->visible() && - ConvertPointToViewAndHitTest(this, close_button_, point)) { - return HTCLOSE; - } else if (size_button_->visible() && - ConvertPointToViewAndHitTest(this, size_button_, point)) { - return HTMAXBUTTON; - } else if (minimize_button_->visible() && - ConvertPointToViewAndHitTest(this, minimize_button_, point)) { - return HTMINBUTTON; - } else if (menu_button_->visible() && - ConvertPointToViewAndHitTest(this, menu_button_, point)) { - return HTMENU; - } - return HTNOWHERE; -} - void FrameCaptionButtonContainerView::UpdateCaptionButtonState(bool animate) { bool size_button_visible = (model_->IsVisible(CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE) ||
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view.h b/ash/frame/caption_buttons/frame_caption_button_container_view.h index 3d48344..27c7f66dc 100644 --- a/ash/frame/caption_buttons/frame_caption_button_container_view.h +++ b/ash/frame/caption_buttons/frame_caption_button_container_view.h
@@ -93,11 +93,6 @@ // Tell the window controls to reset themselves to the normal state. void ResetWindowControls(); - // Determines the window HT* code for the caption button at |point|. Returns - // HTNOWHERE if |point| is not over any of the caption buttons. |point| must - // be in the coordinates of the FrameCaptionButtonContainerView. - int NonClientHitTest(const gfx::Point& point) const; - // Updates the caption buttons' state based on the caption button model's // state. A parent view should relayout to reflect the change in states. void UpdateCaptionButtonState(bool animate);
diff --git a/ash/frame/caption_buttons/frame_size_button.cc b/ash/frame/caption_buttons/frame_size_button.cc index 630ca590..4b3a8c8d 100644 --- a/ash/frame/caption_buttons/frame_size_button.cc +++ b/ash/frame/caption_buttons/frame_size_button.cc
@@ -13,6 +13,7 @@ #include "base/i18n/rtl.h" #include "base/metrics/user_metrics.h" #include "ui/aura/window.h" +#include "ui/base/hit_test.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/views/widget/widget.h" #include "ui/wm/core/coordinate_conversion.h" @@ -48,7 +49,9 @@ FrameSizeButton::FrameSizeButton(views::ButtonListener* listener, views::Widget* frame, FrameSizeButtonDelegate* delegate) - : FrameCaptionButton(listener, CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE), + : FrameCaptionButton(listener, + CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, + HTMAXBUTTON), frame_(frame), delegate_(delegate), set_buttons_to_snap_mode_delay_ms_(kSetButtonsToSnapModeDelayMs),
diff --git a/ash/frame/custom_frame_view_ash.cc b/ash/frame/custom_frame_view_ash.cc index 7da880d..3317b5b 100644 --- a/ash/frame/custom_frame_view_ash.cc +++ b/ash/frame/custom_frame_view_ash.cc
@@ -11,9 +11,9 @@ #include "ash/frame/caption_buttons/frame_caption_button.h" #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/frame/default_frame_header.h" -#include "ash/frame/frame_border_hit_test.h" #include "ash/frame/header_view.h" #include "ash/public/cpp/ash_constants.h" +#include "ash/public/cpp/frame_border_hit_test.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h" #include "ash/public/cpp/window_properties.h" @@ -353,9 +353,7 @@ } int CustomFrameViewAsh::NonClientHitTest(const gfx::Point& point) { - return FrameBorderNonClientHitTest(this, header_view_->GetBackButton(), - header_view_->caption_button_container(), - point); + return FrameBorderNonClientHitTest(this, point); } void CustomFrameViewAsh::GetWindowMask(const gfx::Size& size,
diff --git a/ash/frame/custom_frame_view_ash_unittest.cc b/ash/frame/custom_frame_view_ash_unittest.cc index 6b4b50f..d7c5f140 100644 --- a/ash/frame/custom_frame_view_ash_unittest.cc +++ b/ash/frame/custom_frame_view_ash_unittest.cc
@@ -494,6 +494,7 @@ // back key sequence. generator->MoveMouseTo( header_view->GetBackButton()->GetBoundsInScreen().CenterPoint()); + generator->ClickLeftButton(); EXPECT_EQ(1, target_back_press.accelerator_count()); EXPECT_EQ(1, target_back_release.accelerator_count());
diff --git a/ash/frame/frame_border_hit_test.cc b/ash/frame/frame_border_hit_test.cc deleted file mode 100644 index d3cf03b1..0000000 --- a/ash/frame/frame_border_hit_test.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/frame_border_hit_test.h" - -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/public/cpp/ash_constants.h" -#include "ash/shell_port.h" -#include "ui/base/hit_test.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" -#include "ui/views/window/non_client_view.h" - -namespace ash { - -int FrameBorderNonClientHitTest( - views::NonClientFrameView* view, - const views::View* back_button, - const FrameCaptionButtonContainerView* caption_button_container, - const gfx::Point& point_in_widget) { - gfx::Rect expanded_bounds = view->bounds(); - int outside_bounds = kResizeOutsideBoundsSize; - - if (ShellPort::Get()->IsTouchDown()) - outside_bounds *= kResizeOutsideBoundsScaleForTouch; - expanded_bounds.Inset(-outside_bounds, -outside_bounds); - - if (!expanded_bounds.Contains(point_in_widget)) - return HTNOWHERE; - - // Check the frame first, as we allow a small area overlapping the contents - // to be used for resize handles. - views::Widget* frame = view->GetWidget(); - bool can_ever_resize = frame->widget_delegate()->CanResize(); - // Don't allow overlapping resize handles when the window is maximized or - // fullscreen, as it can't be resized in those states. - int resize_border = kResizeInsideBoundsSize; - if (frame->IsMaximized() || frame->IsFullscreen()) { - resize_border = 0; - can_ever_resize = false; - } - int frame_component = view->GetHTComponentForFrame( - point_in_widget, resize_border, resize_border, kResizeAreaCornerSize, - kResizeAreaCornerSize, can_ever_resize); - if (frame_component != HTNOWHERE) - return frame_component; - - int client_component = - frame->client_view()->NonClientHitTest(point_in_widget); - if (client_component != HTNOWHERE) - return client_component; - - if (caption_button_container->visible()) { - gfx::Point point_in_caption_button_container(point_in_widget); - views::View::ConvertPointFromWidget(caption_button_container, - &point_in_caption_button_container); - int caption_button_component = caption_button_container->NonClientHitTest( - point_in_caption_button_container); - if (caption_button_component != HTNOWHERE) - return caption_button_component; - } - - if (back_button) { - gfx::Point point_in_back_button(point_in_widget); - views::View::ConvertPointFromWidget(back_button, &point_in_back_button); - // Using HTMENU as a placeholder to pass through the event to button. - if (back_button->GetLocalBounds().Contains(point_in_back_button)) - return HTMENU; - } - // Caption is a safe default. - return HTCAPTION; -} - -} // namespace ash
diff --git a/ash/frame/frame_border_hit_test.h b/ash/frame/frame_border_hit_test.h deleted file mode 100644 index f70d6173..0000000 --- a/ash/frame/frame_border_hit_test.h +++ /dev/null
@@ -1,32 +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 ASH_FRAME_FRAME_BORDER_HIT_TEST_H_ -#define ASH_FRAME_FRAME_BORDER_HIT_TEST_H_ - -#include "ash/ash_export.h" - -namespace gfx { -class Point; -} - -namespace views { -class NonClientFrameView; -class View; -} - -namespace ash { - -class FrameCaptionButtonContainerView; - -// Returns the HitTestCompat for the specified point. -ASH_EXPORT int FrameBorderNonClientHitTest( - views::NonClientFrameView* view, - const views::View* back_button, - const FrameCaptionButtonContainerView* caption_button_container, - const gfx::Point& point_in_widget); - -} // namespace ash - -#endif // ASH_FRAME_FRAME_BORDER_HIT_TEST_H_
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index 09658e0..77320d0 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -46,6 +46,8 @@ "ash_typography.h", "ash_view_ids.h", "config.h", + "frame_border_hit_test.cc", + "frame_border_hit_test.h", "immersive/immersive_context.cc", "immersive/immersive_context.h", "immersive/immersive_focus_watcher.h",
diff --git a/ash/public/cpp/frame_border_hit_test.cc b/ash/public/cpp/frame_border_hit_test.cc new file mode 100644 index 0000000..151d675 --- /dev/null +++ b/ash/public/cpp/frame_border_hit_test.cc
@@ -0,0 +1,72 @@ +// 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 "ash/public/cpp/frame_border_hit_test.h" + +#include "ash/public/cpp/ash_constants.h" +#include "ui/aura/env.h" +#include "ui/base/hit_test.h" +#include "ui/views/view_properties.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" +#include "ui/views/window/non_client_view.h" + +namespace ash { + +int FrameBorderNonClientHitTest(views::NonClientFrameView* view, + const gfx::Point& point_in_widget) { + gfx::Rect expanded_bounds = view->bounds(); + int outside_bounds = kResizeOutsideBoundsSize; + + if (aura::Env::GetInstance()->is_touch_down()) + outside_bounds *= kResizeOutsideBoundsScaleForTouch; + expanded_bounds.Inset(-outside_bounds, -outside_bounds); + + if (!expanded_bounds.Contains(point_in_widget)) + return HTNOWHERE; + + // Check the frame first, as we allow a small area overlapping the contents + // to be used for resize handles. + views::Widget* widget = view->GetWidget(); + bool can_ever_resize = widget->widget_delegate()->CanResize(); + // Don't allow overlapping resize handles when the window is maximized or + // fullscreen, as it can't be resized in those states. + int resize_border = kResizeInsideBoundsSize; + if (widget->IsMaximized() || widget->IsFullscreen()) { + resize_border = 0; + can_ever_resize = false; + } + int frame_component = view->GetHTComponentForFrame( + point_in_widget, resize_border, resize_border, kResizeAreaCornerSize, + kResizeAreaCornerSize, can_ever_resize); + if (frame_component != HTNOWHERE) + return frame_component; + + int client_component = + widget->client_view()->NonClientHitTest(point_in_widget); + if (client_component != HTNOWHERE) + return client_component; + + // Check if it intersects with children (frame caption button, back button, + // etc.). + gfx::Point point_in_non_client_view(point_in_widget); + views::View::ConvertPointFromWidget(widget->non_client_view(), + &point_in_non_client_view); + for (views::View* target_view = + widget->non_client_view()->GetEventHandlerForPoint( + point_in_non_client_view); + target_view; target_view = target_view->parent()) { + int target_component = + target_view->GetProperty(views::kHitTestComponentKey); + if (target_component != HTNOWHERE) + return target_component; + if (target_view == widget->non_client_view()) + break; + } + + // Caption is a safe default. + return HTCAPTION; +} + +} // namespace ash
diff --git a/ash/public/cpp/frame_border_hit_test.h b/ash/public/cpp/frame_border_hit_test.h new file mode 100644 index 0000000..f5c7a76 --- /dev/null +++ b/ash/public/cpp/frame_border_hit_test.h
@@ -0,0 +1,27 @@ +// 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 ASH_PUBLIC_CPP_FRAME_BORDER_HIT_TEST_H_ +#define ASH_PUBLIC_CPP_FRAME_BORDER_HIT_TEST_H_ + +#include "ash/public/cpp/ash_public_export.h" + +namespace gfx { +class Point; +} + +namespace views { +class NonClientFrameView; +} // namespace views + +namespace ash { + +// Returns the HitTestCompat for the specified point. +ASH_PUBLIC_EXPORT int FrameBorderNonClientHitTest( + views::NonClientFrameView* view, + const gfx::Point& point_in_widget); + +} // namespace ash + +#endif // ASH_PUBLIC_CPP_FRAME_BORDER_HIT_TEST_H_
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc index b50e206..e08334d 100644 --- a/ash/shell/shell_delegate_impl.cc +++ b/ash/shell/shell_delegate_impl.cc
@@ -31,10 +31,6 @@ return std::make_unique<TestKeyboardUI>(); } -NetworkingConfigDelegate* ShellDelegateImpl::GetNetworkingConfigDelegate() { - return nullptr; -} - std::unique_ptr<ash::ScreenshotDelegate> ShellDelegateImpl::CreateScreenshotDelegate() { return std::make_unique<TestScreenshotDelegate>();
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h index 45a5c61..43a10bb5 100644 --- a/ash/shell/shell_delegate_impl.h +++ b/ash/shell/shell_delegate_impl.h
@@ -28,7 +28,6 @@ bool CanShowWindowForUser(aura::Window* window) const override; void PreInit() override; std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override; - NetworkingConfigDelegate* GetNetworkingConfigDelegate() override; std::unique_ptr<ScreenshotDelegate> CreateScreenshotDelegate() override; AccessibilityDelegate* CreateAccessibilityDelegate() override; ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h index 49831b8..4c884765 100644 --- a/ash/shell_delegate.h +++ b/ash/shell_delegate.h
@@ -31,7 +31,6 @@ namespace ash { class AccessibilityDelegate; -class NetworkingConfigDelegate; class ScreenshotDelegate; // Delegate of the Shell. @@ -54,9 +53,6 @@ // Create a shell-specific keyboard::KeyboardUI. virtual std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() = 0; - // Returns the delegate. May be null in tests. - virtual NetworkingConfigDelegate* GetNetworkingConfigDelegate() = 0; - // TODO(jamescook): Replace with a mojo-compatible interface. virtual std::unique_ptr<ScreenshotDelegate> CreateScreenshotDelegate() = 0;
diff --git a/ash/shell_delegate_mash.cc b/ash/shell_delegate_mash.cc index 21d36d09..bcd5ea4e 100644 --- a/ash/shell_delegate_mash.cc +++ b/ash/shell_delegate_mash.cc
@@ -65,13 +65,6 @@ return nullptr; } -NetworkingConfigDelegate* ShellDelegateMash::GetNetworkingConfigDelegate() { - // TODO(mash): Provide a real implementation, perhaps by folding its behavior - // into an ash-side network information cache. http://crbug.com/651157 - NOTIMPLEMENTED_LOG_ONCE(); - return nullptr; -} - std::unique_ptr<ScreenshotDelegate> ShellDelegateMash::CreateScreenshotDelegate() { return std::make_unique<ScreenshotDelegateMash>();
diff --git a/ash/shell_delegate_mash.h b/ash/shell_delegate_mash.h index 18f9fa7..2ae8231 100644 --- a/ash/shell_delegate_mash.h +++ b/ash/shell_delegate_mash.h
@@ -26,7 +26,6 @@ bool CanShowWindowForUser(aura::Window* window) const override; void PreInit() override; std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override; - NetworkingConfigDelegate* GetNetworkingConfigDelegate() override; std::unique_ptr<ScreenshotDelegate> CreateScreenshotDelegate() override; AccessibilityDelegate* CreateAccessibilityDelegate() override; ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
diff --git a/ash/system/network/network_list.cc b/ash/system/network/network_list.cc index f1ec7ee..0b8cb3d7 100644 --- a/ash/system/network/network_list.cc +++ b/ash/system/network/network_list.cc
@@ -21,7 +21,6 @@ #include "ash/system/network/network_info.h" #include "ash/system/network/network_row_title_view.h" #include "ash/system/network/network_state_list_detailed_view.h" -#include "ash/system/networking_config_delegate.h" #include "ash/system/power/power_status.h" #include "ash/system/tray/hover_highlight_view.h" #include "ash/system/tray/system_menu_button.h" @@ -825,14 +824,10 @@ views::View* NetworkListView::CreateControlledByExtensionView( const NetworkInfo& info) { - NetworkingConfigDelegate* networking_config_delegate = - Shell::Get()->shell_delegate()->GetNetworkingConfigDelegate(); - if (!networking_config_delegate) - return nullptr; - std::unique_ptr<const NetworkingConfigDelegate::ExtensionInfo> - extension_info = - networking_config_delegate->LookUpExtensionForNetwork(info.guid); - if (!extension_info) + const chromeos::NetworkState* network = + NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid( + info.guid); + if (!network || !network->captive_portal_provider()) return nullptr; views::ImageView* controlled_icon = TrayPopupUtils::CreateMainImageView(); @@ -840,7 +835,7 @@ gfx::CreateVectorIcon(kCaptivePortalIcon, kMenuIconColor)); controlled_icon->SetTooltipText(l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_EXTENSION_CONTROLLED_WIFI, - base::UTF8ToUTF16(extension_info->extension_name))); + base::UTF8ToUTF16(network->captive_portal_provider()->name))); controlled_icon->set_id(VIEW_ID_EXTENSION_CONTROLLED_WIFI); return controlled_icon; }
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc index aed8fc9..a703838 100644 --- a/ash/system/network/vpn_list_view.cc +++ b/ash/system/network/vpn_list_view.cc
@@ -54,17 +54,19 @@ // Indicates whether |network| belongs to this VPN provider. bool VpnProviderMatchesNetwork(const VPNProvider& provider, const chromeos::NetworkState& network) { - // Never display non-VPN networks or ARC VPNs. - if (network.type() != shill::kTypeVPN) + const chromeos::NetworkState::VpnProviderInfo* network_vpn_provider = + network.vpn_provider(); + // Never display non-VPN networks or VPNs with no provider info. + if (network.type() != shill::kTypeVPN || !network_vpn_provider) return false; // Package name is the vpn provider id for ArcVPNProvider in network state. - if (network.vpn_provider_type() == shill::kProviderArcVpn) { + if (network_vpn_provider->type == shill::kProviderArcVpn) { return provider.provider_type == VPNProvider::ARC_VPN && - network.vpn_provider_id() == provider.package_name; - } else if (network.vpn_provider_type() == shill::kProviderThirdPartyVpn) { + network_vpn_provider->id == provider.package_name; + } else if (network_vpn_provider->type == shill::kProviderThirdPartyVpn) { return provider.provider_type == VPNProvider::THIRD_PARTY_VPN && - network.vpn_provider_id() == provider.app_id; + network_vpn_provider->id == provider.app_id; } else { return provider.provider_type == VPNProvider::BUILT_IN_VPN; } @@ -362,7 +364,7 @@ for (const chromeos::NetworkState* const& network : networks) { if (!network->IsConnectingOrConnected()) break; - if (network->vpn_provider_type() != shill::kProviderArcVpn) + if (network->GetVpnProviderType() != shill::kProviderArcVpn) continue; bool found_provider = false;
diff --git a/ash/system/networking_config_delegate.cc b/ash/system/networking_config_delegate.cc deleted file mode 100644 index 55cb48b..0000000 --- a/ash/system/networking_config_delegate.cc +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/networking_config_delegate.h" - -namespace ash { - -NetworkingConfigDelegate::ExtensionInfo::ExtensionInfo(const std::string& id, - const std::string& name) - : extension_id(id), extension_name(name) {} - -NetworkingConfigDelegate::ExtensionInfo::~ExtensionInfo() = default; - -} // namespace ash
diff --git a/ash/system/networking_config_delegate.h b/ash/system/networking_config_delegate.h deleted file mode 100644 index b040e70..0000000 --- a/ash/system/networking_config_delegate.h +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_ -#define ASH_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_ - -#include <memory> -#include <string> - -#include "ash/ash_export.h" -#include "base/macros.h" - -namespace ash { - -// This delegate allows the UI code in ash, e.g. |NetworkStateListDetailedView|, -// to access the |NetworkingConfigService| in order to determine whether the -// configuration of a network identified by its |guid| is controlled by -// an extension. -// TODO(crbug.com/651157): Eliminate this delegate. Information about extension -// controlled networks should be provided by a mojo service that caches data at -// the NetworkState level. -class NetworkingConfigDelegate { - public: - // A struct that provides information about the extension controlling the - // configuration of a network. - struct ASH_EXPORT ExtensionInfo { - ExtensionInfo(const std::string& id, const std::string& name); - ~ExtensionInfo(); - std::string extension_id; - std::string extension_name; - }; - - virtual ~NetworkingConfigDelegate() {} - - // Returns information about the extension registered to control configuration - // of the network |guid|. Returns null if no extension is registered. - virtual std::unique_ptr<const ExtensionInfo> LookUpExtensionForNetwork( - const std::string& guid) = 0; - - private: - DISALLOW_ASSIGN(NetworkingConfigDelegate); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc index 3fb790f..720a706f 100644 --- a/ash/test_shell_delegate.cc +++ b/ash/test_shell_delegate.cc
@@ -31,10 +31,6 @@ return std::make_unique<TestKeyboardUI>(); } -NetworkingConfigDelegate* TestShellDelegate::GetNetworkingConfigDelegate() { - return nullptr; -} - std::unique_ptr<ScreenshotDelegate> TestShellDelegate::CreateScreenshotDelegate() { return std::make_unique<TestScreenshotDelegate>();
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h index 5577171f..ab05b16 100644 --- a/ash/test_shell_delegate.h +++ b/ash/test_shell_delegate.h
@@ -22,7 +22,6 @@ bool CanShowWindowForUser(aura::Window* window) const override; void PreInit() override; std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override; - NetworkingConfigDelegate* GetNetworkingConfigDelegate() override; std::unique_ptr<ScreenshotDelegate> CreateScreenshotDelegate() override; AccessibilityDelegate* CreateAccessibilityDelegate() override; ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
diff --git a/ash/wm/panels/panel_frame_view.cc b/ash/wm/panels/panel_frame_view.cc index 8fc1912..a0c0c80e 100644 --- a/ash/wm/panels/panel_frame_view.cc +++ b/ash/wm/panels/panel_frame_view.cc
@@ -6,8 +6,8 @@ #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/frame/default_frame_header.h" -#include "ash/frame/frame_border_hit_test.h" #include "ash/public/cpp/ash_constants.h" +#include "ash/public/cpp/frame_border_hit_test.h" #include "ash/shell.h" #include "ash/wm/resize_handle_window_targeter.h" #include "ash/wm/window_util.h" @@ -123,8 +123,7 @@ int PanelFrameView::NonClientHitTest(const gfx::Point& point) { if (!frame_header_) return HTNOWHERE; - return FrameBorderNonClientHitTest(this, nullptr, caption_button_container_, - point); + return FrameBorderNonClientHitTest(this, point); } void PanelFrameView::OnPaint(gfx::Canvas* canvas) {
diff --git a/base/post_task_and_reply_with_result_internal.h b/base/post_task_and_reply_with_result_internal.h index 6f50de8..881f4bad 100644 --- a/base/post_task_and_reply_with_result_internal.h +++ b/base/post_task_and_reply_with_result_internal.h
@@ -5,6 +5,7 @@ #ifndef BASE_POST_TASK_AND_REPLY_WITH_RESULT_INTERNAL_H_ #define BASE_POST_TASK_AND_REPLY_WITH_RESULT_INTERNAL_H_ +#include <memory> #include <utility> #include "base/callback.h" @@ -16,15 +17,17 @@ // Adapts a function that produces a result via a return value to // one that returns via an output parameter. template <typename ReturnType> -void ReturnAsParamAdapter(OnceCallback<ReturnType()> func, ReturnType* result) { - *result = std::move(func).Run(); +void ReturnAsParamAdapter(OnceCallback<ReturnType()> func, + std::unique_ptr<ReturnType>* result) { + result->reset(new ReturnType(std::move(func).Run())); } // Adapts a T* result to a callblack that expects a T. template <typename TaskReturnType, typename ReplyArgType> void ReplyAdapter(OnceCallback<void(ReplyArgType)> callback, - TaskReturnType* result) { - std::move(callback).Run(std::move(*result)); + std::unique_ptr<TaskReturnType>* result) { + DCHECK(result->get()); + std::move(callback).Run(std::move(**result)); } } // namespace internal
diff --git a/base/task/cancelable_task_tracker.h b/base/task/cancelable_task_tracker.h index e5e6b5e..b7f6d3f 100644 --- a/base/task/cancelable_task_tracker.h +++ b/base/task/cancelable_task_tracker.h
@@ -38,6 +38,7 @@ #include <stdint.h> +#include <memory> #include <utility> #include "base/base_export.h" @@ -82,7 +83,7 @@ const Location& from_here, OnceCallback<TaskReturnType()> task, OnceCallback<void(ReplyArgType)> reply) { - TaskReturnType* result = new TaskReturnType(); + auto* result = new std::unique_ptr<TaskReturnType>(); return PostTaskAndReply( task_runner, from_here, BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>,
diff --git a/base/task_runner_util.h b/base/task_runner_util.h index d79f5b85..7ae085b 100644 --- a/base/task_runner_util.h +++ b/base/task_runner_util.h
@@ -5,6 +5,7 @@ #ifndef BASE_TASK_RUNNER_UTIL_H_ #define BASE_TASK_RUNNER_UTIL_H_ +#include <memory> #include <utility> #include "base/bind.h" @@ -37,7 +38,8 @@ OnceCallback<void(ReplyArgType)> reply) { DCHECK(task); DCHECK(reply); - TaskReturnType* result = new TaskReturnType(); + // std::unique_ptr used to avoid the need of a default constructor. + auto* result = new std::unique_ptr<TaskReturnType>(); return task_runner->PostTaskAndReply( from_here, BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>, std::move(task),
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc index 44baad47..c6d4997 100644 --- a/base/task_runner_util_unittest.cc +++ b/base/task_runner_util_unittest.cc
@@ -66,6 +66,20 @@ EXPECT_FALSE(foo.get()); } +struct FooWithoutDefaultConstructor { + explicit FooWithoutDefaultConstructor(int value) : value(value) {} + int value; +}; + +FooWithoutDefaultConstructor CreateFooWithoutDefaultConstructor(int value) { + return FooWithoutDefaultConstructor(value); +} + +void SaveFooWithoutDefaultConstructor(int* output_value, + FooWithoutDefaultConstructor input) { + *output_value = input.value; +} + } // namespace TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResult) { @@ -73,8 +87,8 @@ MessageLoop message_loop; PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE, - Bind(&ReturnFourtyTwo), - Bind(&StoreValue, &result)); + BindOnce(&ReturnFourtyTwo), + BindOnce(&StoreValue, &result)); RunLoop().RunUntilIdle(); @@ -86,8 +100,8 @@ MessageLoop message_loop; PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE, - Bind(&ReturnFourtyTwo), - Bind(&StoreDoubleValue, &result)); + BindOnce(&ReturnFourtyTwo), + BindOnce(&StoreDoubleValue, &result)); RunLoop().RunUntilIdle(); @@ -100,7 +114,7 @@ MessageLoop message_loop; PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE, - Bind(&CreateFoo), Bind(&ExpectFoo)); + BindOnce(&CreateFoo), BindOnce(&ExpectFoo)); RunLoop().RunUntilIdle(); @@ -114,7 +128,8 @@ MessageLoop message_loop; PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE, - Bind(&CreateScopedFoo), Bind(&ExpectScopedFoo)); + BindOnce(&CreateScopedFoo), + BindOnce(&ExpectScopedFoo)); RunLoop().RunUntilIdle(); @@ -122,4 +137,20 @@ EXPECT_EQ(1, g_foo_free_count); } +TEST(TaskRunnerHelpersTest, + PostTaskAndReplyWithResultWithoutDefaultConstructor) { + const int kSomeVal = 17; + + MessageLoop message_loop; + int actual = 0; + PostTaskAndReplyWithResult( + message_loop.task_runner().get(), FROM_HERE, + BindOnce(&CreateFooWithoutDefaultConstructor, kSomeVal), + BindOnce(&SaveFooWithoutDefaultConstructor, &actual)); + + RunLoop().RunUntilIdle(); + + EXPECT_EQ(kSomeVal, actual); +} + } // namespace base
diff --git a/base/task_scheduler/post_task.h b/base/task_scheduler/post_task.h index d757c85..12c5b715 100644 --- a/base/task_scheduler/post_task.h +++ b/base/task_scheduler/post_task.h
@@ -5,6 +5,7 @@ #ifndef BASE_TASK_SCHEDULER_POST_TASK_H_ #define BASE_TASK_SCHEDULER_POST_TASK_H_ +#include <memory> #include <utility> #include "base/base_export.h" @@ -152,7 +153,7 @@ const TaskTraits& traits, OnceCallback<TaskReturnType()> task, OnceCallback<void(ReplyArgType)> reply) { - TaskReturnType* result = new TaskReturnType(); + auto* result = new std::unique_ptr<TaskReturnType>(); return PostTaskWithTraitsAndReply( from_here, traits, BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>, std::move(task),
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 2f558e39..eb0d633 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -2589,6 +2589,12 @@ ]) } } else { + # placeholder native libraries never go into bundles, since they are + # only used for pre-L Android releases. Use the invoker variable to + # avoid GN errors when the target defines them. + assert(!defined(invoker.native_lib_placeholders) || + invoker.native_lib_placeholders != []) + _final_deps += [ ":$_merge_manifest_target", ":$_build_config_target",
diff --git a/build/fuchsia/sdk.sha1 b/build/fuchsia/sdk.sha1 index ce4087c..d0c37bc 100644 --- a/build/fuchsia/sdk.sha1 +++ b/build/fuchsia/sdk.sha1
@@ -1 +1 @@ -0250d4201e9f4e1324362859cf38d37ba3f473d8 \ No newline at end of file +c4a06fe7a901ee3c23359052bd7d9e448d8207ce \ No newline at end of file
diff --git a/cc/animation/scroll_offset_animation_curve.cc b/cc/animation/scroll_offset_animation_curve.cc index dad0ee2..39d75dc2 100644 --- a/cc/animation/scroll_offset_animation_curve.cc +++ b/cc/animation/scroll_offset_animation_curve.cc
@@ -171,35 +171,37 @@ return curve_clone; } -static double VelocityBasedDurationBound(gfx::Vector2dF old_delta, - double old_normalized_velocity, - double old_duration, - gfx::Vector2dF new_delta) { +static base::TimeDelta VelocityBasedDurationBound( + gfx::Vector2dF old_delta, + double old_normalized_velocity, + base::TimeDelta old_duration, + gfx::Vector2dF new_delta) { double old_delta_max_dimension = MaximumDimension(old_delta); double new_delta_max_dimension = MaximumDimension(new_delta); // If we are already at the target, stop animating. if (std::abs(new_delta_max_dimension) < kEpsilon) - return 0; + return base::TimeDelta(); // Guard against division by zero. if (std::abs(old_delta_max_dimension) < kEpsilon || std::abs(old_normalized_velocity) < kEpsilon) { - return std::numeric_limits<double>::infinity(); + return base::TimeDelta::Max(); } // Estimate how long it will take to reach the new target at our present // velocity, with some fudge factor to account for the "ease out". - double old_true_velocity = - old_normalized_velocity * old_delta_max_dimension / old_duration; + double old_true_velocity = old_normalized_velocity * old_delta_max_dimension / + old_duration.InSecondsF(); double bound = (new_delta_max_dimension / old_true_velocity) * 2.5f; // If bound < 0 we are moving in the opposite direction. - return bound < 0 ? std::numeric_limits<double>::infinity() : bound; + return bound < 0 ? base::TimeDelta::Max() + : base::TimeDelta::FromSecondsD(bound); } void ScrollOffsetAnimationCurve::UpdateTarget( - double t, + base::TimeDelta t, const gfx::ScrollOffset& new_target) { if (std::abs(MaximumDimension(target_value_.DeltaFrom(new_target))) < kEpsilon) { @@ -207,41 +209,38 @@ return; } - base::TimeDelta delayed_by = base::TimeDelta::FromSecondsD( - std::max(0.0, last_retarget_.InSecondsF() - t)); - t = std::max(t, last_retarget_.InSecondsF()); + base::TimeDelta delayed_by = std::max(base::TimeDelta(), last_retarget_ - t); + t = std::max(t, last_retarget_); - gfx::ScrollOffset current_position = - GetValue(base::TimeDelta::FromSecondsD(t)); + gfx::ScrollOffset current_position = GetValue(t); gfx::Vector2dF old_delta = target_value_.DeltaFrom(initial_value_); gfx::Vector2dF new_delta = new_target.DeltaFrom(current_position); // The last segement was of zero duration. if ((total_animation_duration_ - last_retarget_).is_zero()) { - DCHECK_EQ(t, last_retarget_.InSecondsF()); + DCHECK_EQ(t, last_retarget_); total_animation_duration_ = SegmentDuration(new_delta, duration_behavior_, delayed_by); target_value_ = new_target; return; } - double old_duration = - (total_animation_duration_ - last_retarget_).InSecondsF(); + base::TimeDelta old_duration = total_animation_duration_ - last_retarget_; double old_normalized_velocity = timing_function_->Velocity( - (t - last_retarget_.InSecondsF()) / old_duration); + ((t - last_retarget_).InSecondsF()) / old_duration.InSecondsF()); // Use the velocity-based duration bound when it is less than the constant // segment duration. This minimizes the "rubber-band" bouncing effect when // old_normalized_velocity is large and new_delta is small. - double new_duration = std::min( - SegmentDuration(new_delta, duration_behavior_, delayed_by).InSecondsF(), - VelocityBasedDurationBound(old_delta, old_normalized_velocity, - old_duration, new_delta)); + base::TimeDelta new_duration = + std::min(SegmentDuration(new_delta, duration_behavior_, delayed_by), + VelocityBasedDurationBound(old_delta, old_normalized_velocity, + old_duration, new_delta)); - if (new_duration < kEpsilon) { + if (new_duration.InSecondsF() < kEpsilon) { // We are already at or very close to the new target. Stop animating. target_value_ = new_target; - total_animation_duration_ = base::TimeDelta::FromSecondsD(t); + total_animation_duration_ = t; return; } @@ -249,13 +248,14 @@ // To match the "true" velocity in px/sec we must adjust this slope for // differences in duration and scroll delta between old and new curves. double new_normalized_velocity = - old_normalized_velocity * (new_duration / old_duration) * + old_normalized_velocity * + (new_duration.InSecondsF() / old_duration.InSecondsF()) * (MaximumDimension(old_delta) / MaximumDimension(new_delta)); initial_value_ = current_position; target_value_ = new_target; - total_animation_duration_ = base::TimeDelta::FromSecondsD(t + new_duration); - last_retarget_ = base::TimeDelta::FromSecondsD(t); + total_animation_duration_ = t + new_duration; + last_retarget_ = t; timing_function_ = EaseOutWithInitialVelocity(new_normalized_velocity); }
diff --git a/cc/animation/scroll_offset_animation_curve.h b/cc/animation/scroll_offset_animation_curve.h index d471d2b..6924c1e 100644 --- a/cc/animation/scroll_offset_animation_curve.h +++ b/cc/animation/scroll_offset_animation_curve.h
@@ -59,7 +59,7 @@ // relative to the start of the animation. The duration is recomputed based // on the DurationBehavior the curve was constructed with. The timing // function is an ease-in-out cubic bezier modified to preserve velocity at t. - void UpdateTarget(double t, const gfx::ScrollOffset& new_target); + void UpdateTarget(base::TimeDelta t, const gfx::ScrollOffset& new_target); // Shifts the entire curve by a delta without affecting its shape or timing. // Used for scroll anchoring adjustments that happen during scroll animations
diff --git a/cc/animation/scroll_offset_animation_curve_unittest.cc b/cc/animation/scroll_offset_animation_curve_unittest.cc index 522ea2d..cd308a70 100644 --- a/cc/animation/scroll_offset_animation_curve_unittest.cc +++ b/cc/animation/scroll_offset_animation_curve_unittest.cc
@@ -148,7 +148,8 @@ curve->GetValue(base::TimeDelta::FromSecondsD(duration)).y(), 0.0002f); - curve->UpdateTarget(duration / 2, gfx::ScrollOffset(0.0, 9900.0)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(duration / 2), + gfx::ScrollOffset(0.0, 9900.0)); EXPECT_NEAR(duration * 1.5, curve->Duration().InSecondsF(), 0.0002f); EXPECT_NEAR( @@ -163,7 +164,8 @@ curve->GetValue(base::TimeDelta::FromSecondsD(duration * 1.5)).y(), 0.0002f); - curve->UpdateTarget(duration, gfx::ScrollOffset(0.0, 7200.0)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(duration), + gfx::ScrollOffset(0.0, 7200.0)); // A closer target at high velocity reduces the duration. EXPECT_NEAR(duration * 1.0794, curve->Duration().InSecondsF(), 0.0002f); @@ -187,16 +189,19 @@ curve->SetInitialValue(gfx::ScrollOffset()); double smallDeltaDuration = curve->Duration().InSecondsF(); - curve->UpdateTarget(0.01f, gfx::ScrollOffset(0.f, 300.f)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.01f), + gfx::ScrollOffset(0.f, 300.f)); double mediumDeltaDuration = curve->Duration().InSecondsF(); - curve->UpdateTarget(0.01f, gfx::ScrollOffset(0.f, 500.f)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.01f), + gfx::ScrollOffset(0.f, 500.f)); double largeDeltaDuration = curve->Duration().InSecondsF(); EXPECT_GT(smallDeltaDuration, mediumDeltaDuration); EXPECT_GT(mediumDeltaDuration, largeDeltaDuration); - curve->UpdateTarget(0.01f, gfx::ScrollOffset(0.f, 5000.f)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.01f), + gfx::ScrollOffset(0.f, 5000.f)); EXPECT_EQ(largeDeltaDuration, curve->Duration().InSecondsF()); } @@ -215,7 +220,8 @@ base::TimeDelta::FromSecondsD(delay_in_seconds)); EXPECT_NEAR(curve_duration, curve->Duration().InSecondsF(), 0.0002f); - curve->UpdateTarget(0.01f, gfx::ScrollOffset(0.f, 500.f)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.01f), + gfx::ScrollOffset(0.f, 500.f)); EXPECT_GT(curve_duration, curve->Duration().InSecondsF()); EXPECT_EQ(gfx::ScrollOffset(0.f, 500.f), curve->target_value()); } @@ -232,7 +238,8 @@ EXPECT_EQ(0.f, curve->Duration().InSecondsF()); // Re-targeting when animation duration is 0. - curve->UpdateTarget(-0.01, gfx::ScrollOffset(0.f, 300.f)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.01), + gfx::ScrollOffset(0.f, 300.f)); double duration = ScrollOffsetAnimationCurve::SegmentDuration( gfx::Vector2dF(0.f, 200.f), @@ -243,7 +250,8 @@ // Re-targeting before last_retarget_, the difference should be accounted for // in duration. - curve->UpdateTarget(-0.01, gfx::ScrollOffset(0.f, 500.f)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.01), + gfx::ScrollOffset(0.f, 500.f)); duration = ScrollOffsetAnimationCurve::SegmentDuration( gfx::Vector2dF(0.f, 500.f), ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA, @@ -283,13 +291,15 @@ base::TimeDelta()) .InSecondsF() + 0.05; - curve->UpdateTarget(0.05, gfx::ScrollOffset(0.f, 200.f)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(0.05), + gfx::ScrollOffset(0.f, 200.f)); EXPECT_NEAR(expected_duration, curve->Duration().InSecondsF(), 0.0002f); // Re-target 2, this should set total_animation_duration to t, which is // last_retarget_. This is what would cause the DCHECK failure in // crbug.com/645317. - curve->UpdateTarget(-0.145, gfx::ScrollOffset(0.f, 300.f)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.145), + gfx::ScrollOffset(0.f, 300.f)); EXPECT_NEAR(0.05, curve->Duration().InSecondsF(), 0.0002f); // Re-target 3, this should set total_animation_duration based on new_delta. @@ -301,7 +311,8 @@ ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA, base::TimeDelta::FromSecondsD(0.15)) .InSecondsF(); - curve->UpdateTarget(-0.1, gfx::ScrollOffset(0.f, 500.f)); + curve->UpdateTarget(base::TimeDelta::FromSecondsD(-0.1), + gfx::ScrollOffset(0.f, 500.f)); EXPECT_NEAR(expected_duration, curve->Duration().InSecondsF(), 0.0002f); }
diff --git a/cc/animation/scroll_offset_animations_impl.cc b/cc/animation/scroll_offset_animations_impl.cc index 2e1a274..00ce5bf 100644 --- a/cc/animation/scroll_offset_animations_impl.cc +++ b/cc/animation/scroll_offset_animations_impl.cc
@@ -110,7 +110,7 @@ // t = -delayed_by. trimmed -= delayed_by; - curve->UpdateTarget(trimmed.InSecondsF(), new_target); + curve->UpdateTarget(trimmed, new_target); TRACE_EVENT_INSTANT1("cc", "ScrollAnimationUpdateTarget", TRACE_EVENT_SCOPE_THREAD, "UpdatedDuration", curve->Duration().InMillisecondsF());
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h index a3530604..807f140 100644 --- a/cc/input/input_handler.h +++ b/cc/input/input_handler.h
@@ -16,6 +16,7 @@ #include "cc/input/scroll_state.h" #include "cc/input/scrollbar.h" #include "cc/input/touch_action.h" +#include "cc/trees/element_id.h" #include "cc/trees/swap_promise_monitor.h" namespace gfx { @@ -227,10 +228,11 @@ virtual ScrollElasticityHelper* CreateScrollElasticityHelper() = 0; // Called by the single-threaded UI Compositor to get or set the scroll offset - // on the impl side. Retruns false if |layer_id| isn't in the active tree. - virtual bool GetScrollOffsetForLayer(int layer_id, + // on the impl side. Returns false if |element_id| isn't in the active tree. + virtual bool GetScrollOffsetForLayer(ElementId element_id, gfx::ScrollOffset* offset) = 0; - virtual bool ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset) = 0; + virtual bool ScrollLayerTo(ElementId element_id, + const gfx::ScrollOffset& offset) = 0; virtual bool ScrollingShouldSwitchtoMainThread() = 0;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index ebdb74e..cffc4df 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -813,24 +813,28 @@ return scroll_elasticity_helper_.get(); } -bool LayerTreeHostImpl::GetScrollOffsetForLayer(int layer_id, +bool LayerTreeHostImpl::GetScrollOffsetForLayer(ElementId element_id, gfx::ScrollOffset* offset) { - LayerImpl* layer = active_tree()->FindActiveTreeLayerById(layer_id); - if (!layer) + ScrollTree& scroll_tree = active_tree()->property_trees()->scroll_tree; + ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(element_id); + if (!scroll_node) return false; - - *offset = layer->CurrentScrollOffset(); + *offset = scroll_tree.current_scroll_offset(element_id); return true; } -bool LayerTreeHostImpl::ScrollLayerTo(int layer_id, +bool LayerTreeHostImpl::ScrollLayerTo(ElementId element_id, const gfx::ScrollOffset& offset) { - LayerImpl* layer = active_tree()->FindActiveTreeLayerById(layer_id); - if (!layer) + ScrollTree& scroll_tree = active_tree()->property_trees()->scroll_tree; + ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(element_id); + if (!scroll_node) return false; - layer->ScrollBy( - ScrollOffsetToVector2dF(offset - layer->CurrentScrollOffset())); + scroll_tree.ScrollBy( + scroll_node, + ScrollOffsetToVector2dF(offset - + scroll_tree.current_scroll_offset(element_id)), + active_tree()); return true; }
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 862fcaf7..a4b2e504 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -283,9 +283,10 @@ std::unique_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor( ui::LatencyInfo* latency) override; ScrollElasticityHelper* CreateScrollElasticityHelper() override; - bool GetScrollOffsetForLayer(int layer_id, + bool GetScrollOffsetForLayer(ElementId element_id, gfx::ScrollOffset* offset) override; - bool ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset) override; + bool ScrollLayerTo(ElementId element_id, + const gfx::ScrollOffset& offset) override; bool ScrollingShouldSwitchtoMainThread() override; // BrowserControlsOffsetManagerClient implementation.
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc index d94e2fe..45f7556 100644 --- a/cc/trees/property_tree.cc +++ b/cc/trees/property_tree.cc
@@ -1243,6 +1243,14 @@ } #endif +ScrollNode* ScrollTree::FindNodeFromElementId(ElementId id) { + auto iterator = property_trees()->element_id_to_scroll_node_index.find(id); + if (iterator == property_trees()->element_id_to_scroll_node_index.end()) + return nullptr; + + return Node(iterator->second); +} + const ScrollNode* ScrollTree::FindNodeFromElementId(ElementId id) const { auto iterator = property_trees()->element_id_to_scroll_node_index.find(id); if (iterator == property_trees()->element_id_to_scroll_node_index.end())
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h index 39dac92370..a41eb36f 100644 --- a/cc/trees/property_tree.h +++ b/cc/trees/property_tree.h
@@ -460,6 +460,7 @@ void CopyCompleteTreeState(const ScrollTree& other); #endif + ScrollNode* FindNodeFromElementId(ElementId id); const ScrollNode* FindNodeFromElementId(ElementId id) const; private:
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml b/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml index 621d041..d7cbb66 100644 --- a/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml +++ b/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml
@@ -5,11 +5,11 @@ <TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:paddingTop="8dp" - android:paddingBottom="8dp" - android:paddingStart="52dp" - android:paddingEnd="16dp" + android:id="@+id/suggestion_text" + android:layout_marginStart="@dimen/keyboard_accessory_suggestion_margin" + android:paddingEnd="@dimen/keyboard_accessory_suggestion_margin" + android:gravity="center_vertical|start" android:fillViewport="true" - android:layout_height="48dp" + android:layout_height="@dimen/keyboard_accessory_suggestion_height" android:textAppearance="@style/BlackTitle1" android:layout_width="match_parent"/> \ No newline at end of file
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 052adae..d28a612 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -129,6 +129,9 @@ <dimen name="keyboard_accessory_padding">6dp</dimen> <dimen name="keyboard_accessory_sheet_height">330dp</dimen> <dimen name="keyboard_accessory_text_size">14sp</dimen> + <dimen name="keyboard_accessory_suggestion_margin">16dp</dimen> + <dimen name="keyboard_accessory_suggestion_height">48dp</dimen> + <dimen name="keyboard_accessory_suggestion_icon_size">20dp</dimen> <!-- Password generation popup dimensions --> <dimen name="password_generation_divider_height">1dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java index 361c3f33..0717dffa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
@@ -173,10 +173,10 @@ .isStartupSuccessfullyCompleted(); try { - new AsyncTask<Context, Void, DefaultInfo>() { + new AsyncTask<Void, Void, DefaultInfo>() { @Override - protected DefaultInfo doInBackground(Context... params) { - Context context = params[0]; + protected DefaultInfo doInBackground(Void... params) { + Context context = ContextUtils.getApplicationContext(); PackageManager pm = context.getPackageManager(); @@ -222,8 +222,7 @@ getDefaultBrowserUmaState(info), MobileDefaultBrowserState.NUM_ENTRIES); } } - .executeOnExecutor( - AsyncTask.THREAD_POOL_EXECUTOR, ContextUtils.getApplicationContext()); + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } catch (RejectedExecutionException ex) { // Fail silently here since this is not a critical task. }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java index a5055965..a31b40c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.autofill.keyboard_accessory; +import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.support.annotation.LayoutRes; import android.support.annotation.Nullable; @@ -146,6 +147,19 @@ private final String mContentDescription; private final boolean mIsPassword; private final @Nullable Callback<Item> mItemSelectedCallback; + private final @Nullable FaviconProvider mFaviconProvider; + + /** + * Items will call a class that implements this interface to request a favicon. + */ + interface FaviconProvider { + /** + * Starts a request for a favicon. The callback can be called either asynchronously or + * synchronously (depending on whether the icon was cached). + * @param favicon The icon to be used for this Item. If null, use the default icon. + */ + void fetchFavicon(Callback<Bitmap> favicon); + } /** * Creates a new Item of type {@link ItemType#LABEL}. It is not interactive. @@ -153,8 +167,9 @@ * @param contentDescription The description of this item (i.e. used for accessibility). */ public static Item createLabel(String caption, String contentDescription) { - return new Item(ItemType.LABEL, caption, contentDescription, false, null); + return new Item(ItemType.LABEL, caption, contentDescription, false, null, null); } + /** * Creates a new Item of type {@link ItemType#SUGGESTION} if has a callback, otherwise, it * will be {@link ItemType#NON_INTERACTIVE_SUGGESTION}. It usually is part of a list of @@ -165,20 +180,21 @@ * @param itemSelectedCallback A click on this item will invoke this callback. Optional. */ public static Item createSuggestion(String caption, String contentDescription, - boolean isPassword, @Nullable Callback<Item> itemSelectedCallback) { + boolean isPassword, @Nullable Callback<Item> itemSelectedCallback, + @Nullable FaviconProvider faviconProvider) { if (itemSelectedCallback == null) { return new Item(ItemType.NON_INTERACTIVE_SUGGESTION, caption, contentDescription, - isPassword, null); + isPassword, null, faviconProvider); } return new Item(ItemType.SUGGESTION, caption, contentDescription, isPassword, - itemSelectedCallback); + itemSelectedCallback, faviconProvider); } /** * Creates an Item of type {@link ItemType#DIVIDER}. Basically, it's a horizontal line. */ public static Item createDivider() { - return new Item(ItemType.DIVIDER, null, null, false, null); + return new Item(ItemType.DIVIDER, null, null, false, null, null); } /** @@ -190,7 +206,7 @@ */ public static Item createOption( String caption, String contentDescription, Callback<Item> callback) { - return new Item(ItemType.OPTION, caption, contentDescription, false, callback); + return new Item(ItemType.OPTION, caption, contentDescription, false, callback, null); } /** @@ -200,14 +216,17 @@ * @param contentDescription The description of this item (i.e. used for accessibility). * @param isPassword If true, the displayed caption is transformed into stars. * @param itemSelectedCallback If the Item is interactive, a click on it will trigger this. + * @param faviconProvider */ private Item(@ItemType int type, String caption, String contentDescription, - boolean isPassword, @Nullable Callback<Item> itemSelectedCallback) { + boolean isPassword, @Nullable Callback<Item> itemSelectedCallback, + @Nullable FaviconProvider faviconProvider) { mType = type; mCaption = caption; mContentDescription = contentDescription; mIsPassword = isPassword; mItemSelectedCallback = itemSelectedCallback; + mFaviconProvider = faviconProvider; } /** @@ -249,6 +268,14 @@ public Callback<Item> getItemSelectedCallback() { return mItemSelectedCallback; } + + public void fetchFavicon(Callback<Bitmap> faviconCallback) { + if (mFaviconProvider == null) { + faviconCallback.onResult(null); // Use default icon without provider. + return; + } + mFaviconProvider.fetchFavicon(faviconCallback); + } } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java index ddc1283..ba35074 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java
@@ -4,8 +4,10 @@ package org.chromium.chrome.browser.autofill.keyboard_accessory; +import android.graphics.Bitmap; import android.support.annotation.Nullable; +import org.chromium.base.Callback; import org.chromium.base.annotations.CalledByNative; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; @@ -92,11 +94,11 @@ != 0 : "Controller was destroyed but the bridge wasn't!"; nativeOnFillingTriggered( mNativeView, item.isPassword(), item.getCaption()); - }); + }, this::fetchFavicon); continue; case ItemType.NON_INTERACTIVE_SUGGESTION: items[i] = Item.createSuggestion( - text[i], description[i], isPassword[i] == 1, null); + text[i], description[i], isPassword[i] == 1, null, this::fetchFavicon); continue; case ItemType.DIVIDER: items[i] = Item.createDivider(); @@ -113,6 +115,13 @@ return items; } + public void fetchFavicon(Callback<Bitmap> faviconCallback) { + assert mNativeView != 0 : "Favicon was requested after the bridge was destroyed!"; + nativeOnFaviconRequested(mNativeView, faviconCallback); + } + + private native void nativeOnFaviconRequested( + long nativePasswordAccessoryViewAndroid, Callback<Bitmap> faviconCallback); private native void nativeOnFillingTriggered( long nativePasswordAccessoryViewAndroid, boolean isPassword, String textToFill); private native void nativeOnOptionSelected(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java index 7d5d49a4..0341e215 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
@@ -5,7 +5,9 @@ package org.chromium.chrome.browser.autofill.keyboard_accessory; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; import android.support.v7.content.res.AppCompatResources; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -56,6 +58,11 @@ } } + interface FaviconProvider { + @Nullable + Bitmap getFavicon(); + } + /** * Creates the passwords tab. * @param context The {@link Context} containing resources like icons and layouts for this tab.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java index 02b3782..f212860 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
@@ -4,6 +4,12 @@ package org.chromium.chrome.browser.autofill.keyboard_accessory; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.support.v4.view.MarginLayoutParamsCompat; +import android.support.v7.content.res.AppCompatResources; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.method.PasswordTransformationMethod; @@ -12,6 +18,7 @@ import android.view.ViewGroup; import android.widget.TextView; +import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item; import org.chromium.chrome.browser.modelutil.RecyclerViewAdapter; @@ -39,7 +46,7 @@ false)); case ItemType.SUGGESTION: // Intentional fallthrough. case ItemType.NON_INTERACTIVE_SUGGESTION: { - return new TextViewHolder( + return new IconTextViewHolder( LayoutInflater.from(parent.getContext()) .inflate(R.layout.password_accessory_sheet_suggestion, parent, false)); @@ -79,24 +86,82 @@ * Returns the text view of this item if there is one. * @return Returns a {@link TextView}. */ - private TextView getTextView() { + protected TextView getTextView() { return (TextView) itemView; } @Override protected void bind(Item item) { super.bind(item); - if (item.isPassword()) { - getTextView().setTransformationMethod(new PasswordTransformationMethod()); - } + getTextView().setTransformationMethod( + item.isPassword() ? new PasswordTransformationMethod() : null); getTextView().setText(item.getCaption()); if (item.getItemSelectedCallback() != null) { getTextView().setOnClickListener( src -> item.getItemSelectedCallback().onResult(item)); + } else { + getTextView().setOnClickListener(null); } } } + /** + * Holds a TextView that represents a list entry. + */ + static class IconTextViewHolder extends TextViewHolder { + private final TextView mSuggestionText; + private final int mMargin; + private final int mIconSize; + + IconTextViewHolder(View itemView) { + super(itemView); + mSuggestionText = itemView.findViewById(R.id.suggestion_text); + mMargin = itemView.getContext().getResources().getDimensionPixelSize( + R.dimen.keyboard_accessory_suggestion_margin); + mIconSize = itemView.getContext().getResources().getDimensionPixelSize( + R.dimen.keyboard_accessory_suggestion_icon_size); + } + + @Override + protected TextView getTextView() { + return mSuggestionText; + } + + @Override + protected void bind(Item item) { + super.bind(item); + ViewGroup.MarginLayoutParams params = + new ViewGroup.MarginLayoutParams(mSuggestionText.getLayoutParams()); + MarginLayoutParamsCompat.setMarginEnd(params, mMargin); + if (!item.isPassword()) { + setIconForBitmap(null); // Set the default icon, then try to get a better one. + item.fetchFavicon(this::setIconForBitmap); + MarginLayoutParamsCompat.setMarginStart(params, mMargin); + } else { + ApiCompatibilityUtils.setCompoundDrawablesRelative( + mSuggestionText, null, null, null, null); + MarginLayoutParamsCompat.setMarginStart(params, 2 * mMargin + mIconSize); + } + mSuggestionText.setLayoutParams(params); + } + + private void setIconForBitmap(@Nullable Bitmap favicon) { + Drawable icon; + if (favicon == null) { + icon = AppCompatResources.getDrawable( + itemView.getContext(), R.drawable.ic_globe_36dp); + } else { + icon = new BitmapDrawable(itemView.getContext().getResources(), favicon); + } + if (icon != null) { // AppCompatResources.getDrawable is @Nullable. + icon.setBounds(0, 0, mIconSize, mIconSize); + } + mSuggestionText.setCompoundDrawablePadding(mMargin); + ApiCompatibilityUtils.setCompoundDrawablesRelative( + mSuggestionText, icon, null, null, null); + } + } + static void initializeView(RecyclerView view, RecyclerViewAdapter adapter) { view.setLayoutManager( new LinearLayoutManager(view.getContext(), LinearLayoutManager.VERTICAL, false));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/FileDeletionQueue.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/FileDeletionQueue.java index 3afdd20..aa5691b7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/FileDeletionQueue.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/FileDeletionQueue.java
@@ -67,22 +67,25 @@ System.out.println("dtrainor: Starting " + file.getName()); - mTask = new FileDeletionTask(); - mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, file); + mTask = new FileDeletionTask(file); + mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - private class FileDeletionTask extends AsyncTask<File, Void, Void> { - // AsyncTask implementation. + private class FileDeletionTask extends AsyncTask<Void, Void, Void> { + private final File mFile; + + FileDeletionTask(File file) { + mFile = file; + } + @Override - protected Void doInBackground(File... params) { - System.out.println("dtrainor: Deleting " + params[0].getName()); - mDeleter.onResult(params[0]); + protected Void doInBackground(Void... params) { + mDeleter.onResult(mFile); return null; } @Override protected void onPostExecute(Void result) { - System.out.println("dtrainor: Post"); super.onPostExecute(result); mTask = null; deleteNextFile();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java index d4dd0ee4..67bc6eaa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java
@@ -95,9 +95,9 @@ postResult(callback, ConnectivityCheckResult.ERROR); return; } - new AsyncTask<String, Void, Integer>() { + new AsyncTask<Void, Void, Integer>() { @Override - protected Integer doInBackground(String... strings) { + protected Integer doInBackground(Void... params) { try { HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setInstanceFollowRedirects(false); @@ -127,7 +127,8 @@ protected void onPostExecute(Integer result) { callback.onResult(result); } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java index fa83255..1f626503 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
@@ -66,13 +66,11 @@ private static SyncController sInstance; private static boolean sInitialized; - private final Context mContext; private final ChromeSigninController mChromeSigninController; private final ProfileSyncService mProfileSyncService; private final SyncNotificationController mSyncNotificationController; - private SyncController(Context context) { - mContext = context; + private SyncController() { mChromeSigninController = ChromeSigninController.get(); AndroidSyncSettings.registerObserver(this); mProfileSyncService = ProfileSyncService.get(); @@ -89,7 +87,7 @@ // Create the SyncNotificationController. mSyncNotificationController = new SyncNotificationController( - mContext, PassphraseActivity.class, AccountManagementFragment.class); + PassphraseActivity.class, AccountManagementFragment.class); mProfileSyncService.addSyncStateChangedListener(mSyncNotificationController); updateSyncStateFromAndroid(); @@ -123,15 +121,14 @@ /** * Retrieve the singleton instance of this class. * - * @param context the current context. * @return the singleton instance. */ @Nullable - public static SyncController get(Context context) { + public static SyncController get() { ThreadUtils.assertOnUiThread(); if (!sInitialized) { if (ProfileSyncService.get() != null) { - sInstance = new SyncController(context.getApplicationContext()); + sInstance = new SyncController(); } sInitialized = true; } @@ -139,6 +136,16 @@ } /** + * Retrieve the singleton instance of this class. + * @deprecated Use get with no arguments instead. + * @return the singleton instance. + */ + @Nullable + public static SyncController get(Context context) { + return get(); + } + + /** * Updates sync to reflect the state of the Android sync settings. */ private void updateSyncStateFromAndroid() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java index 147e52f..09ad6399a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
@@ -14,6 +14,7 @@ import android.content.Intent; import android.util.Log; +import org.chromium.base.ContextUtils; import org.chromium.base.ThreadUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; @@ -32,18 +33,15 @@ */ public class SyncNotificationController implements ProfileSyncService.SyncStateChangedListener { private static final String TAG = "SyncNotificationController"; - private final Context mApplicationContext; private final NotificationManagerProxy mNotificationManager; private final Class<? extends Activity> mPassphraseRequestActivity; private final Class<? extends Fragment> mAccountManagementFragment; private final ProfileSyncService mProfileSyncService; - public SyncNotificationController(Context context, - Class<? extends Activity> passphraseRequestActivity, + public SyncNotificationController(Class<? extends Activity> passphraseRequestActivity, Class<? extends Fragment> accountManagementFragment) { - mApplicationContext = context.getApplicationContext(); mNotificationManager = new NotificationManagerProxyImpl( - (NotificationManager) mApplicationContext.getSystemService( + (NotificationManager) ContextUtils.getApplicationContext().getSystemService( Context.NOTIFICATION_SERVICE)); mProfileSyncService = ProfileSyncService.get(); assert mProfileSyncService != null; @@ -95,11 +93,12 @@ * @param intent Intent to send when the user activates the notification. */ private void showSyncNotification(int message, Intent intent) { - String title = mApplicationContext.getString(R.string.app_name); - String text = mApplicationContext.getString(R.string.sign_in_sync) + ": " - + mApplicationContext.getString(message); + Context applicationContext = ContextUtils.getApplicationContext(); + String title = applicationContext.getString(R.string.app_name); + String text = applicationContext.getString(R.string.sign_in_sync) + ": " + + applicationContext.getString(message); - PendingIntent contentIntent = PendingIntent.getActivity(mApplicationContext, 0, intent, 0); + PendingIntent contentIntent = PendingIntent.getActivity(applicationContext, 0, intent, 0); // There is no need to provide a group summary notification because the NOTIFICATION_ID_SYNC // notification id ensures there's only one sync notification at a time. @@ -151,8 +150,8 @@ * @return the intent for opening the settings */ private Intent createSettingsIntent() { - return PreferencesLauncher.createIntentForSettingsPage( - mApplicationContext, mAccountManagementFragment.getCanonicalName()); + return PreferencesLauncher.createIntentForSettingsPage(ContextUtils.getApplicationContext(), + mAccountManagementFragment.getCanonicalName()); } /** @@ -165,7 +164,8 @@ mProfileSyncService.setPassphrasePrompted(true); Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setComponent(new ComponentName(mApplicationContext, mPassphraseRequestActivity)); + intent.setComponent(new ComponentName( + ContextUtils.getApplicationContext(), mPassphraseRequestActivity)); intent.addCategory(Intent.CATEGORY_LAUNCHER); // This activity will become the start of a new task on this history stack. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseActivity.java index 4146eee..98365b3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseActivity.java
@@ -138,7 +138,7 @@ @Override public void onPassphraseCanceled() { // Re add the notification. - SyncController.get(this).getSyncNotificationController().syncStateChanged(); + SyncController.get().getSyncNotificationController().syncStateChanged(); finish(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java index 04ec30d..abc60bf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -77,10 +77,14 @@ * transitioning between states. */ int NONE = -1; + // Values are used for indexing mStateRatios, should start from 0 + // and can't have gaps. Additionally order is important for these, + // they go from smallest to largest. int HIDDEN = 0; int PEEK = 1; int HALF = 2; int FULL = 3; + int SCROLLING = 4; } @@ -141,8 +145,6 @@ * Information about the different scroll states of the sheet. Order is important for these, * they go from smallest to largest. */ - private static final int[] sStates = - new int[] {SheetState.HIDDEN, SheetState.PEEK, SheetState.HALF, SheetState.FULL}; private final float[] mStateRatios = new float[4]; /** The interpolator that the height animator uses. */ @@ -1405,7 +1407,7 @@ */ @SheetState private int getTargetSheetState(float sheetHeight, float yVelocity) { - if (sheetHeight <= getMinOffsetPx()) return sStates[getMinSwipableSheetState()]; + if (sheetHeight <= getMinOffsetPx()) return getMinSwipableSheetState(); if (sheetHeight >= getMaxOffsetPx()) return SheetState.FULL; boolean isMovingDownward = yVelocity < 0; @@ -1413,15 +1415,15 @@ // First, find the two states that the sheet height is between. @SheetState - int nextState = sStates[getMinSwipableSheetState()]; + int nextState = getMinSwipableSheetState(); @SheetState int prevState = nextState; - for (int i = getMinSwipableSheetState(); i < sStates.length; i++) { - if (sStates[i] == SheetState.HALF && shouldSkipHalfState) continue; - if (sStates[i] == SheetState.PEEK && !mSheetContent.isPeekStateEnabled()) continue; + for (@SheetState int i = getMinSwipableSheetState(); i <= SheetState.FULL; i++) { + if (i == SheetState.HALF && shouldSkipHalfState) continue; + if (i == SheetState.PEEK && !mSheetContent.isPeekStateEnabled()) continue; prevState = nextState; - nextState = sStates[i]; + nextState = i; // The values in PanelState are ascending, they should be kept that way in order for // this to work. if (sheetHeight >= getSheetHeightForState(prevState)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java index b605cc7..4300a02 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java
@@ -222,10 +222,10 @@ } private static Item createSuggestion(String caption, Callback<Item> callback) { - return Item.createSuggestion(caption, "Description_" + caption, false, callback); + return Item.createSuggestion(caption, "Description_" + caption, false, callback, null); } private static Item createPassword(String caption) { - return Item.createSuggestion(caption, "Description_" + caption, true, null); + return Item.createSuggestion(caption, "Description_" + caption, true, null, null); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java index 0fe63e6..87b287a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java
@@ -110,15 +110,13 @@ ThreadUtils.runOnUiThreadBlocking( () -> mModel.add(Item.createSuggestion( - "Name Suggestion", null, false, item -> clicked.set(true)))); + "Name Suggestion", null, false, item -> clicked.set(true), null))); CriteriaHelper.pollUiThread(Criteria.equals(1, () -> mView.get().getChildCount())); - assertThat(mView.get().getChildAt(0), instanceOf(TextView.class)); - TextView suggestion = (TextView) mView.get().getChildAt(0); - assertThat(suggestion.getText(), is("Name Suggestion")); + assertThat(getFirstSuggestion().getText(), is("Name Suggestion")); - ThreadUtils.runOnUiThreadBlocking(suggestion::performClick); + ThreadUtils.runOnUiThreadBlocking(getFirstSuggestion()::performClick); assertThat(clicked.get(), is(true)); } @@ -130,18 +128,21 @@ ThreadUtils.runOnUiThreadBlocking( () - -> mModel.add(Item.createSuggestion( - "Password Suggestion", null, true, item -> clicked.set(true)))); + -> mModel.add(Item.createSuggestion("Password Suggestion", null, true, + item -> clicked.set(true), null))); CriteriaHelper.pollUiThread(Criteria.equals(1, () -> mView.get().getChildCount())); - assertThat(mView.get().getChildAt(0), instanceOf(TextView.class)); - TextView suggestion = (TextView) mView.get().getChildAt(0); - assertThat(suggestion.getText(), is("Password Suggestion")); - assertThat(suggestion.getTransformationMethod(), + assertThat(getFirstSuggestion().getText(), is("Password Suggestion")); + assertThat(getFirstSuggestion().getTransformationMethod(), instanceOf(PasswordTransformationMethod.class)); - ThreadUtils.runOnUiThreadBlocking(suggestion::performClick); + ThreadUtils.runOnUiThreadBlocking(getFirstSuggestion()::performClick); assertThat(clicked.get(), is(true)); } + + private TextView getFirstSuggestion() { + assertThat(mView.get().getChildAt(0), instanceOf(TextView.class)); + return (TextView) mView.get().getChildAt(0); + } } \ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java index 2dd1876..6c147390 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
@@ -33,7 +33,6 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.base.test.util.RetryOnFailure; @@ -41,20 +40,19 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.engagement.SiteEngagementService; -import org.chromium.chrome.browser.infobar.InfoBar; +import org.chromium.chrome.browser.permissions.PermissionDialogController; +import org.chromium.chrome.browser.permissions.PermissionTestRule; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.preferences.website.ContentSetting; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.widget.RoundedIconGenerator; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.util.InfoBarUtil; import org.chromium.chrome.test.util.browser.TabTitleObserver; import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy.NotificationEntry; import org.chromium.components.url_formatter.UrlFormatter; import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; -import org.chromium.net.test.EmbeddedTestServerRule; import java.net.URL; import java.util.ArrayList; @@ -73,7 +71,7 @@ @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) public class NotificationPlatformBridgeTest { @Rule - public EmbeddedTestServerRule mEmbeddedTestServerRule = new EmbeddedTestServerRule(); + public PermissionTestRule mPermissionTestRule = new PermissionTestRule(); @Rule public NotificationTestRule mNotificationTestRule = new NotificationTestRule(); @@ -85,8 +83,8 @@ @Before public void setUp() throws Exception { SiteEngagementService.setParamValuesForTesting(); - mNotificationTestRule.loadUrl( - mEmbeddedTestServerRule.getServer().getURL(NOTIFICATION_TEST_PAGE)); + mNotificationTestRule.loadUrl(mPermissionTestRule.getURL(NOTIFICATION_TEST_PAGE)); + mPermissionTestRule.setActivity(mNotificationTestRule.getActivity()); } @SuppressWarnings("MissingFail") @@ -102,31 +100,11 @@ } } - private InfoBar getInfobarBlocking() { - CriteriaHelper.pollUiThread(new Criteria() { - @Override - public boolean isSatisfied() { - return !mNotificationTestRule.getInfoBars().isEmpty(); - } - }); - List<InfoBar> infoBars = mNotificationTestRule.getInfoBars(); - Assert.assertEquals(1, infoBars.size()); - return infoBars.get(0); - } - - private void waitForInfobarToClose() { - CriteriaHelper.pollUiThread(new Criteria() { - @Override - public boolean isSatisfied() { - return mNotificationTestRule.getInfoBars().isEmpty(); - } - }); - Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size()); - } - private void checkThatShowNotificationIsDenied() throws Exception { showNotification("MyNotification", "{}"); - waitForTitle("TypeError: No notification permission has been granted for this origin."); + waitForTitle( + "TypeError: Failed to execute 'showNotification' on 'ServiceWorkerRegistration': " + + "No notification permission has been granted for this origin."); // Ideally we'd wait a little here, but it's hard to wait for things that shouldn't happen. Assert.assertTrue(mNotificationTestRule.getNotificationEntries().isEmpty()); @@ -138,7 +116,7 @@ @Override public Double call() throws Exception { return SiteEngagementService.getForProfile(Profile.getLastUsedProfile()) - .getScore(mEmbeddedTestServerRule.getOrigin()); + .getScore(mPermissionTestRule.getOrigin()); } }); } catch (ExecutionException ex) { @@ -151,52 +129,36 @@ * Verifies that notifcations cannot be shown without permission, and that dismissing or denying * the infobar works correctly. */ - //@LargeTest - //@Feature({"Browser", "Notifications"}) - // crbug.com/707528 + @LargeTest + @Feature({"Browser", "Notifications"}) @Test - @DisabledTest public void testPermissionDenied() throws Exception { // Notifications permission should initially be prompt, and showing should fail. Assert.assertEquals("\"default\"", runJavaScript("Notification.permission")); checkThatShowNotificationIsDenied(); - // Notification.requestPermission() should show the notifications infobar. - Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size()); - runJavaScript("Notification.requestPermission(sendToTest)"); - InfoBar infoBar = getInfobarBlocking(); + PermissionTestRule.PermissionUpdateWaiter updateWaiter = + new PermissionTestRule.PermissionUpdateWaiter( + "denied: ", mNotificationTestRule.getActivity()); - // Dismissing the infobar should pass prompt to the requestPermission callback. - Assert.assertTrue(InfoBarUtil.clickCloseButton(infoBar)); - waitForInfobarToClose(); - waitForTitle("default"); // See https://crbug.com/434547. + mNotificationTestRule.getActivity().getActivityTab().addObserver(updateWaiter); - // Notifications permission should still be prompt. - Assert.assertEquals("\"default\"", runJavaScript("Notification.permission")); - checkThatShowNotificationIsDenied(); - - // Notification.requestPermission() should show the notifications infobar again. - runJavaScript("Notification.requestPermission(sendToTest)"); - infoBar = getInfobarBlocking(); - - // Denying the infobar should pass denied to the requestPermission callback. - Assert.assertTrue(InfoBarUtil.clickSecondaryButton(infoBar)); - waitForInfobarToClose(); - waitForTitle("denied"); + mPermissionTestRule.runDenyTest(updateWaiter, NOTIFICATION_TEST_PAGE, + "Notification.requestPermission(addCountAndSendToTest)", 1, false, true); // This should have caused notifications permission to become denied. Assert.assertEquals("\"denied\"", runJavaScript("Notification.permission")); checkThatShowNotificationIsDenied(); // Reload page to ensure the block is persisted. - mNotificationTestRule.loadUrl( - mEmbeddedTestServerRule.getServer().getURL(NOTIFICATION_TEST_PAGE)); + mNotificationTestRule.loadUrl(mPermissionTestRule.getURL(NOTIFICATION_TEST_PAGE)); // Notification.requestPermission() should immediately pass denied to the callback without - // showing an infobar. + // showing a dialog. runJavaScript("Notification.requestPermission(sendToTest)"); waitForTitle("denied"); - Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size()); + Assert.assertEquals( + null, PermissionDialogController.getInstance().getCurrentDialogForTesting()); // Notifications permission should still be denied. Assert.assertEquals("\"denied\"", runJavaScript("Notification.permission")); @@ -206,29 +168,25 @@ /** * Verifies granting permission via the infobar. */ - //@MediumTest - //@Feature({"Browser", "Notifications"}) - // crbug.com/707528 + @MediumTest + @Feature({"Browser", "Notifications"}) @Test - @DisabledTest public void testPermissionGranted() throws Exception { // Notifications permission should initially be prompt, and showing should fail. Assert.assertEquals("\"default\"", runJavaScript("Notification.permission")); checkThatShowNotificationIsDenied(); - // Notification.requestPermission() should show the notifications infobar. - Assert.assertEquals(0, mNotificationTestRule.getInfoBars().size()); - runJavaScript("Notification.requestPermission(sendToTest)"); - InfoBar infoBar = getInfobarBlocking(); + PermissionTestRule.PermissionUpdateWaiter updateWaiter = + new PermissionTestRule.PermissionUpdateWaiter( + "granted: ", mNotificationTestRule.getActivity()); - // Accepting the infobar should pass granted to the requestPermission callback. - Assert.assertTrue(InfoBarUtil.clickPrimaryButton(infoBar)); - waitForInfobarToClose(); - waitForTitle("granted"); + mNotificationTestRule.getActivity().getActivityTab().addObserver(updateWaiter); + + mPermissionTestRule.runAllowTest(updateWaiter, NOTIFICATION_TEST_PAGE, + "Notification.requestPermission(addCountAndSendToTest)", 1, false, true); // Reload page to ensure the grant is persisted. - mNotificationTestRule.loadUrl( - mEmbeddedTestServerRule.getServer().getURL(NOTIFICATION_TEST_PAGE)); + mNotificationTestRule.loadUrl(mPermissionTestRule.getURL(NOTIFICATION_TEST_PAGE)); // Notifications permission should now be granted, and showing should succeed. Assert.assertEquals("\"granted\"", runJavaScript("Notification.permission")); @@ -245,13 +203,13 @@ @RetryOnFailure public void testDefaultNotificationProperties() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); Context context = InstrumentationRegistry.getTargetContext(); Notification notification = showAndGetNotification("MyNotification", "{body: 'Hello'}"); - String expectedOrigin = UrlFormatter.formatUrlForSecurityDisplayOmitScheme( - mEmbeddedTestServerRule.getOrigin()); + String expectedOrigin = + UrlFormatter.formatUrlForSecurityDisplayOmitScheme(mPermissionTestRule.getOrigin()); // Validate the contents of the notification. Assert.assertEquals("MyNotification", NotificationTestUtil.getExtraTitle(notification)); @@ -309,7 +267,7 @@ @Feature({"Browser", "Notifications"}) public void testShowNotificationWithTextAction() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); Notification notification = showAndGetNotification("MyNotification", "{ " @@ -340,7 +298,7 @@ @Feature({"Browser", "Notifications"}) public void testReplyToNotification() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); Context context = InstrumentationRegistry.getTargetContext(); UserActionTester actionTester = new UserActionTester(); @@ -388,7 +346,7 @@ @Feature({"Browser", "Notifications"}) public void testReplyToNotificationWithEmptyReply() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); Context context = InstrumentationRegistry.getTargetContext(); // +0.5 engagement from navigating to the test page. @@ -448,7 +406,7 @@ @Feature({"Browser", "Notifications"}) public void testReplyToNotificationWithNoRemoteInput() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); // +0.5 engagement from navigating to the test page. Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0); @@ -475,7 +433,7 @@ @Feature({"Browser", "Notifications"}) public void testNotificationRenotifyProperty() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); Notification notification = showAndGetNotification("MyNotification", "{ tag: 'myTag', renotify: true }"); @@ -492,7 +450,7 @@ @Feature({"Browser", "Notifications"}) public void testNotificationSilentProperty() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); Notification notification = showAndGetNotification("MyNotification", "{ silent: true }"); @@ -503,7 +461,7 @@ private void verifyVibrationNotRequestedWhenDisabledInPrefs(String notificationOptions) throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); // Disable notification vibration in preferences. ThreadUtils.runOnUiThreadBlocking(new Runnable() { @@ -557,7 +515,7 @@ @Feature({"Browser", "Notifications"}) public void testNotificationVibrateCustomPattern() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); // By default, vibration is enabled in notifications. ThreadUtils.runOnUiThreadBlocking(new Runnable() { @@ -590,7 +548,7 @@ @Feature({"Browser", "Notifications"}) public void testShowNotificationWithBadge() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); Notification notification = showAndGetNotification("MyNotification", "{badge: 'badge.png'}"); @@ -604,8 +562,8 @@ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Custom badges are only supported on M+. // 1. Check the notification badge. - URL badgeUrl = new URL(mEmbeddedTestServerRule.getServer().getURL( - "/chrome/test/data/notifications/badge.png")); + URL badgeUrl = new URL( + mPermissionTestRule.getURL("/chrome/test/data/notifications/badge.png")); Bitmap bitmap = BitmapFactory.decodeStream(badgeUrl.openStream()); Bitmap expected = bitmap.copy(bitmap.getConfig(), true); NotificationBuilderBase.applyWhiteOverlayToBitmap(expected); @@ -644,7 +602,7 @@ @RetryOnFailure public void testShowNotificationWithIcon() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); Notification notification = showAndGetNotification("MyNotification", "{icon: 'red.png'}"); @@ -667,7 +625,7 @@ @RetryOnFailure public void testShowNotificationWithoutIcon() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); Notification notification = showAndGetNotification("NoIconNotification", "{}"); @@ -686,7 +644,7 @@ RoundedIconGenerator generator = NotificationBuilderBase.createIconGenerator(context.getResources()); - Bitmap generatedIcon = generator.generateIconForUrl(mEmbeddedTestServerRule.getOrigin()); + Bitmap generatedIcon = generator.generateIconForUrl(mPermissionTestRule.getOrigin()); Assert.assertNotNull(generatedIcon); Assert.assertTrue(generatedIcon.sameAs( NotificationTestUtil.getLargeIconFromNotification(context, notification))); @@ -703,7 +661,7 @@ @RetryOnFailure public void testNotificationContentIntentClosesNotification() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); // +0.5 engagement from navigating to the test page. Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0); @@ -749,7 +707,7 @@ @RetryOnFailure public void testNotificationContentIntentCreatesTab() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); Assert.assertEquals( "Expected the notification test page to be the sole tab in the current model", 1, @@ -790,7 +748,7 @@ @Feature({"Browser", "Notifications"}) public void testNotificationTagReplacement() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); // +0.5 engagement from navigating to the test page. Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0); @@ -829,7 +787,7 @@ @Feature({"Browser", "Notifications"}) public void testShowAndCloseMultipleNotifications() throws Exception { mNotificationTestRule.setNotificationContentSettingForOrigin( - ContentSetting.ALLOW, mEmbeddedTestServerRule.getOrigin()); + ContentSetting.ALLOW, mPermissionTestRule.getOrigin()); // +0.5 engagement from navigating to the test page. Assert.assertEquals(0.5, getEngagementScoreBlocking(), 0);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/GeolocationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/GeolocationTest.java index c48c8ac..76d09383 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/GeolocationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/GeolocationTest.java
@@ -44,6 +44,7 @@ @Before public void setUp() throws Exception { + mPermissionRule.setUpActivity(); LocationSettingsTestUtil.setSystemLocationSettingEnabled(true); LocationProviderOverrider.setLocationProviderImpl(new MockLocationProvider()); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java index 5ba0d05..7d62aa21 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java
@@ -6,6 +6,7 @@ import android.support.test.filters.MediumTest; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,6 +35,11 @@ public MediaTest() {} + @Before + public void setUp() throws Exception { + mPermissionRule.setUpActivity(); + } + private void testMediaPermissionsPlumbing(String prefix, String script, int numUpdates, boolean withGesture, boolean isDialog) throws Exception { Tab tab = mPermissionRule.getActivity().getActivityTab();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java index fcfe0b93..a17644d0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.permissions; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,6 +34,11 @@ public PermissionNavigationTest() {} + @Before + public void setUp() throws Exception { + mPermissionRule.setUpActivity(); + } + /** * Check that modal permission prompts and queued permission requests are removed upon * navigation.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java index 9060b07..8ae3be51 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java
@@ -60,7 +60,7 @@ * Waits till a JavaScript callback which updates the page title is called the specified number * of times. The page title is expected to be of the form <prefix>: <count>. */ - protected static class PermissionUpdateWaiter extends EmptyTabObserver { + public static class PermissionUpdateWaiter extends EmptyTabObserver { private CallbackHelper mCallbackHelper; private String mPrefix; private int mExpectedCount; @@ -136,13 +136,19 @@ } private void ruleSetUp() throws Throwable { + // TODO(https://crbug.com/867446): Refactor to use EmbeddedTestServerRule. + mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); + } + + /** + * Starts an activity and listens for info-bars appearing/disappearing. + */ + void setUpActivity() throws InterruptedException { startMainActivityOnBlankPage(); InfoBarContainer container = getActivity().getTabModelSelector().getCurrentTab().getInfoBarContainer(); mListener = new InfoBarTestAnimationListener(); container.addAnimationListener(mListener); - // TODO(yolandyan): refactor to use EmbeddedTestServerRule - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); } private void ruleTearDown() throws Exception { @@ -150,9 +156,16 @@ } protected void setUpUrl(final String url) throws InterruptedException { - loadUrl(mTestServer.getURL(url)); + loadUrl(getURL(url)); } + public String getURL(String url) { + return mTestServer.getURL(url); + } + + public String getOrigin() { + return mTestServer.getURL("/"); + } /** * Simulates clicking a button on an PermissionDialogView. */ @@ -181,23 +194,55 @@ String javascript, int nUpdates, boolean withGesture, boolean isDialog) throws Exception { setUpUrl(url); - if (withGesture) { - runJavaScriptCodeInCurrentTab("functionToRun = '" + javascript + "'"); - TouchCommon.singleClickView(getActivity().getActivityTab().getView()); + runJavaScriptCodeInCurrentTabWithGesture(javascript); } else { runJavaScriptCodeInCurrentTab(javascript); } + replyToPromptAndWaitForUpdates(updateWaiter, true, nUpdates, isDialog); + } + /** + * Runs a permission prompt test that grants the permission and expects the page title to be + * updated in response. + * @param updateWaiter The update waiter to wait for callbacks. Should be added as an observer + * to the current tab prior to calling this method. + * @param javascript The JS function to run in the current tab to execute the test and update + * the page title. + * @param nUpdates How many updates of the page title to wait for. + * @param withGesture True if we require a user gesture to trigger the prompt. + * @param isDialog True if we are expecting a permission dialog, false for an infobar. + * @throws Exception + */ + public void runDenyTest(PermissionUpdateWaiter updateWaiter, final String url, + String javascript, int nUpdates, boolean withGesture, boolean isDialog) + throws Exception { + setUpUrl(url); + if (withGesture) { + runJavaScriptCodeInCurrentTabWithGesture(javascript); + } else { + runJavaScriptCodeInCurrentTab(javascript); + } + replyToPromptAndWaitForUpdates(updateWaiter, false, nUpdates, isDialog); + } + + private void replyToPromptAndWaitForUpdates(PermissionUpdateWaiter updateWaiter, boolean allow, + int nUpdates, boolean isDialog) throws Exception { if (isDialog) { DialogShownCriteria criteria = new DialogShownCriteria("Dialog not shown", true); CriteriaHelper.pollUiThread(criteria); - replyToDialogAndWaitForUpdates(updateWaiter, criteria.getDialog(), nUpdates, true); + replyToDialogAndWaitForUpdates(updateWaiter, criteria.getDialog(), nUpdates, allow); } else { - replyToInfoBarAndWaitForUpdates(updateWaiter, nUpdates, true); + replyToInfoBarAndWaitForUpdates(updateWaiter, nUpdates, allow); } } + private void runJavaScriptCodeInCurrentTabWithGesture(String javascript) + throws InterruptedException, java.util.concurrent.TimeoutException { + runJavaScriptCodeInCurrentTab("functionToRun = '" + javascript + "'"); + TouchCommon.singleClickView(getActivity().getActivityTab().getView()); + } + /** * Replies to an infobar permission prompt and waits for a provided number * of updates to the page title in response.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/QuotaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/QuotaTest.java index bc8cccf6..3b9434a4f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/QuotaTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/QuotaTest.java
@@ -6,6 +6,7 @@ import android.support.test.filters.MediumTest; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -30,6 +31,11 @@ private static final String TEST_FILE = "/content/test/data/android/quota_permissions.html"; + @Before + public void setUp() throws Exception { + mPermissionRule.setUpActivity(); + } + public QuotaTest() {} private void testQuotaPermissionsPlumbing(
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java index ac2abf52..208cad79 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
@@ -149,15 +149,15 @@ Tab firstTab = addTab(mediator, 1111, null); mController.registerPasswordProvider(firstTabProvider); firstTabProvider.notifyObservers(new Item[] { - Item.createSuggestion("FirstPassword", "FirstPassword", true, result -> {})}); + Item.createSuggestion("FirstPassword", "FirstPassword", true, result -> {}, null)}); assertThat(mediator.getPasswordAccessorySheet().getModelForTesting().get(0).getCaption(), is("FirstPassword")); // Simulate creating a second tab: Tab secondTab = addTab(mediator, 2222, firstTab); mController.registerPasswordProvider(secondTabProvider); - secondTabProvider.notifyObservers(new Item[] { - Item.createSuggestion("SecondPassword", "SecondPassword", true, result -> {})}); + secondTabProvider.notifyObservers(new Item[] {Item.createSuggestion( + "SecondPassword", "SecondPassword", true, result -> {}, null)}); assertThat(mediator.getPasswordAccessorySheet().getModelForTesting().get(0).getCaption(), is("SecondPassword"));
diff --git a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java index 2193f099..10430bc 100644 --- a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java +++ b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkServiceConnectionManager.java
@@ -150,12 +150,13 @@ public void disconnectAll(final Context appContext) { if (mConnections.isEmpty()) return; - Connection[] values = mConnections.values().toArray(new Connection[mConnections.size()]); + final Connection[] values = + mConnections.values().toArray(new Connection[mConnections.size()]); mConnections.clear(); - new AsyncTask<Connection, Void, Void>() { + new AsyncTask<Void, Void, Void>() { @Override - protected final Void doInBackground(Connection... values) { + protected final Void doInBackground(Void... params) { for (Connection connection : values) { if (connection.getService() != null) { appContext.unbindService(connection); @@ -163,7 +164,8 @@ } return null; } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, values); + } + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } public WebApkServiceConnectionManager(String category, String action) {
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index a6726bf..8fb66e8 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc
@@ -761,12 +761,6 @@ #endif #if defined(OS_MACOSX) - // On the Mac, the child executable lives at a predefined location within - // the app bundle's versioned directory. - base::PathService::Override(content::CHILD_PROCESS_EXE, - chrome::GetVersionedDirectory().Append( - chrome::kHelperProcessExecutablePath)); - InitMacCrashReporter(command_line, process_type); SetUpInstallerPreferences(command_line); #endif
diff --git a/chrome/app/chrome_main_mac.mm b/chrome/app/chrome_main_mac.mm index 5a37a170..72d4089 100644 --- a/chrome/app/chrome_main_mac.mm +++ b/chrome/app/chrome_main_mac.mm
@@ -13,8 +13,11 @@ #import "base/mac/bundle_locations.h" #import "base/mac/foundation_util.h" #import "base/mac/scoped_nsautorelease_pool.h" +#include "base/path_service.h" #include "base/strings/sys_string_conversions.h" +#include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths_internal.h" +#include "content/public/common/content_paths.h" void SetUpBundleOverrides() { base::mac::ScopedNSAutoreleasePool pool; @@ -23,4 +26,10 @@ NSBundle* base_bundle = chrome::OuterAppBundle(); base::mac::SetBaseBundleID([[base_bundle bundleIdentifier] UTF8String]); + + // On the Mac, the child executable lives at a predefined location within + // the app bundle's versioned directory. + base::PathService::Override(content::CHILD_PROCESS_EXE, + chrome::GetVersionedDirectory().Append( + chrome::kHelperProcessExecutablePath)); }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index a824921..00d178b 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2428,6 +2428,7 @@ "//chrome/browser/android/webapk:proto", "//chrome/services/media_gallery_util:manifest", # TODO(xingliu): Tries to remove this. "//chrome/services/media_gallery_util/public/cpp", + "//components/autofill_assistant/browser", "//components/cdm/browser", "//components/embedder_support/android:web_contents_delegate", "//components/feed:buildflags",
diff --git a/chrome/browser/android/password_manager/password_accessory_view_android.cc b/chrome/browser/android/password_manager/password_accessory_view_android.cc index 4c1a3b3..a4e0a51 100644 --- a/chrome/browser/android/password_manager/password_accessory_view_android.cc +++ b/chrome/browser/android/password_manager/password_accessory_view_android.cc
@@ -9,6 +9,7 @@ #include <memory> #include <vector> +#include "base/android/callback_android.h" #include "base/android/jni_android.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" @@ -16,6 +17,8 @@ #include "jni/PasswordAccessoryBridge_jni.h" #include "ui/android/view_android.h" #include "ui/android/window_android.h" +#include "ui/gfx/android/java_bitmap.h" +#include "ui/gfx/image/image.h" PasswordAccessoryViewAndroid::PasswordAccessoryViewAndroid( PasswordAccessoryController* controller) @@ -71,6 +74,16 @@ env, java_object_, available /* available */); } +void PasswordAccessoryViewAndroid::OnFaviconRequested( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jobject>& j_callback) { + controller_->GetFavicon( + base::BindOnce(&PasswordAccessoryViewAndroid::OnImageFetched, + base::Unretained(this), // Outlives or cancels request. + base::android::ScopedJavaGlobalRef<jobject>(j_callback))); +} + void PasswordAccessoryViewAndroid::OnFillingTriggered( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, @@ -94,6 +107,16 @@ controller_->OnGenerationRequested(); } +void PasswordAccessoryViewAndroid::OnImageFetched( + const base::android::ScopedJavaGlobalRef<jobject>& j_callback, + const gfx::Image& image) { + base::android::ScopedJavaLocalRef<jobject> j_bitmap; + if (!image.IsEmpty()) + j_bitmap = gfx::ConvertToJavaBitmap(image.ToSkBitmap()); + + RunObjectCallbackAndroid(j_callback, j_bitmap); +} + // static std::unique_ptr<PasswordAccessoryViewInterface> PasswordAccessoryViewInterface::Create(
diff --git a/chrome/browser/android/password_manager/password_accessory_view_android.h b/chrome/browser/android/password_manager/password_accessory_view_android.h index c8169ae..cac9a07 100644 --- a/chrome/browser/android/password_manager/password_accessory_view_android.h +++ b/chrome/browser/android/password_manager/password_accessory_view_android.h
@@ -10,6 +10,10 @@ #include "base/android/scoped_java_ref.h" #include "chrome/browser/password_manager/password_accessory_view_interface.h" +namespace gfx { +class Image; +} + class PasswordAccessoryController; // This Android-specific implementation of the |PasswordAccessoryViewInterface| @@ -27,6 +31,10 @@ void OnAutomaticGenerationStatusChanged(bool available) override; // Called from Java via JNI: + void OnFaviconRequested( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jobject>& j_callback); void OnFillingTriggered( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, @@ -40,6 +48,10 @@ const base::android::JavaParamRef<jobject>& obj); private: + void OnImageFetched( + const base::android::ScopedJavaGlobalRef<jobject>& j_callback, + const gfx::Image& image); + // The controller provides data for this view and owns it. PasswordAccessoryController* controller_;
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc index fd6fb396..d3f1f1e5 100644 --- a/chrome/browser/android/tab_android.cc +++ b/chrome/browser/android/tab_android.cc
@@ -33,6 +33,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_android.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/resource_coordinator/tab_load_tracker.h" #include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/sessions/tab_restore_service_factory.h" #include "chrome/browser/sync/glue/synced_tab_delegate_android.h" @@ -343,6 +344,11 @@ std::unique_ptr<content::WebContents> new_contents, bool did_start_load, bool did_finish_load) { + // TODO(crbug.com/836409): TabLoadTracker should not rely on being notified + // directly about tab contents swaps. + resource_coordinator::TabLoadTracker::Get()->SwapTabContents( + old_contents, new_contents.get()); + JNIEnv* env = base::android::AttachCurrentThread(); Java_Tab_swapWebContents(env, weak_java_tab_.get(env), new_contents->GetJavaWebContents(), did_start_load,
diff --git a/chrome/browser/android/vr/BUILD.gn b/chrome/browser/android/vr/BUILD.gn index d4095c9..58e8924 100644 --- a/chrome/browser/android/vr/BUILD.gn +++ b/chrome/browser/android/vr/BUILD.gn
@@ -79,14 +79,19 @@ ":vr_jni_headers", "//base", "//cc", - "//chrome/browser/vr:vr_gl_utils", + "//chrome/browser/ui:ui", "//chrome/browser/vr:vr_common", + "//chrome/browser/vr:vr_gl_utils", + "//chrome/common:common", + "//chrome/common:constants", "//components/omnibox/browser", "//components/rappor", + "//components/search_engines:search_engines", "//content/public/browser", "//content/public/common", "//device/gamepad", "//device/vr", + "//device/vr/buildflags:buildflags", "//services/device/public/mojom", "//services/metrics/public/cpp:ukm_builders", "//services/ui/public/cpp/gpu",
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc index da7d3157..c1ac862 100644 --- a/chrome/browser/autofill/autofill_interactive_uitest.cc +++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -2711,6 +2711,84 @@ ExpectFieldValue("phone", "15125551234"); } +// Test that we can autofill forms that dynamically change the element that +// has been clicked on. +IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, + DynamicFormFill_FirstElementDisappears) { + CreateTestProfile(); + + GURL url = embedded_test_server()->GetURL( + "a.com", "/autofill/dynamic_form_element_invalid.html"); + ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); + TriggerFormFill("firstname"); + + // Wait for the re-fill to happen. + bool has_refilled = false; + ASSERT_TRUE(content::ExecuteScriptAndExtractBool( + GetWebContents(), "hasRefilled()", &has_refilled)); + ASSERT_TRUE(has_refilled); + + // Make sure the new form was filled correctly. + ExpectFieldValue("firstname2", "Milton"); + ExpectFieldValue("address1", "4120 Freidrich Lane"); + ExpectFieldValue("city", "Austin"); + ExpectFieldValue("company", "Initech"); + ExpectFieldValue("email", "red.swingline@initech.com"); + ExpectFieldValue("phone", "15125551234"); +} + +// Test that we can autofill forms that dynamically change the element that +// has been clicked on, even though the form has no name. +IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, + DynamicFormFill_FirstElementDisappearsNoNameForm) { + CreateTestProfile(); + + GURL url = embedded_test_server()->GetURL( + "a.com", "/autofill/dynamic_form_element_invalid_noname_form.html"); + ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); + TriggerFormFill("firstname"); + + // Wait for the re-fill to happen. + bool has_refilled = false; + ASSERT_TRUE(content::ExecuteScriptAndExtractBool( + GetWebContents(), "hasRefilled()", &has_refilled)); + ASSERT_TRUE(has_refilled); + + // Make sure the new form was filled correctly. + ExpectFieldValue("firstname2", "Milton"); + ExpectFieldValue("address1", "4120 Freidrich Lane"); + ExpectFieldValue("city", "Austin"); + ExpectFieldValue("company", "Initech"); + ExpectFieldValue("email", "red.swingline@initech.com"); + ExpectFieldValue("phone", "15125551234"); +} + +// Test that we can autofill forms that dynamically change the element that +// has been clicked on, even though the elements are unowned. +IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, + DynamicFormFill_FirstElementDisappearsUnowned) { + CreateTestProfile(); + + GURL url = embedded_test_server()->GetURL( + "a.com", "/autofill/dynamic_form_element_invalid_unowned.html"); + ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url)); + TriggerFormFill("firstname"); + + // Wait for the re-fill to happen. + bool has_refilled = false; + ASSERT_TRUE(content::ExecuteScriptAndExtractBool( + GetWebContents(), "hasRefilled()", &has_refilled)); + ASSERT_TRUE(has_refilled); + + // Make sure the new form was filled correctly. + ExpectFieldValue("firstname2", "Milton"); + ExpectFieldValue("address1", "4120 Freidrich Lane"); + ExpectFieldValue("city", "Austin"); + ExpectFieldValue("company", "Initech"); + ExpectFieldValue("email", "red.swingline@initech.com"); + ExpectFieldValue("phone", "15125551234"); +} + // Test that credit card fields are never re-filled. IN_PROC_BROWSER_TEST_P(AutofillDynamicFormInteractiveTest, DynamicChangingFormFill_NotForCreditCard) {
diff --git a/chrome/browser/captive_portal/captive_portal_tab_reloader.cc b/chrome/browser/captive_portal/captive_portal_tab_reloader.cc index b5c99d3..f2b3909 100644 --- a/chrome/browser/captive_portal/captive_portal_tab_reloader.cc +++ b/chrome/browser/captive_portal/captive_portal_tab_reloader.cc
@@ -266,8 +266,10 @@ void CaptivePortalTabReloader::ReloadTab() { content::NavigationController* controller = &web_contents_->GetController(); - if (!controller->GetLastCommittedEntry()->GetHasPostData()) + if (controller->GetLastCommittedEntry() && + !controller->GetLastCommittedEntry()->GetHasPostData()) { controller->Reload(content::ReloadType::NORMAL, true); + } } void CaptivePortalTabReloader::MaybeOpenCaptivePortalLoginTab() {
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc index d11a15e..4d586ce 100644 --- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc +++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -33,7 +33,7 @@ const ComponentConfig kConfigs[] = { {"epson-inkjet-printer-escpr", "2.1", "1913a5e0a6cad30b6f03e176177e0d7ed62c5d6700a9c66da556d7c3f5d6a47e"}, - {"cros-termina", "1.1", + {"cros-termina", "70.1", "e9d960f84f628e1f42d05de4046bb5b3154b6f1f65c08412c6af57a29aecaffb"}, {"rtanalytics-light", "4.1", "69f09d33c439c2ab55bbbe24b47ab55cb3f6c0bd1f1ef46eefea3216ec925038"},
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc index 5d019ce8..288f148 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc +++ b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
@@ -1,4 +1,4 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager.h b/chrome/browser/media/webrtc/webrtc_event_log_manager.h index 74c081d6..626dc5b 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_manager.h +++ b/chrome/browser/media/webrtc/webrtc_event_log_manager.h
@@ -1,4 +1,4 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc index 82a6723b..652d94d 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc +++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_common.cc
@@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_common.h b/chrome/browser/media/webrtc/webrtc_event_log_manager_common.h index 4fdb07f..a3b6595 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_manager_common.h +++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_common.h
@@ -1,4 +1,4 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc index 50e9ddb..4046605 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc +++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc
@@ -1,4 +1,4 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.h b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.h index 877856b..7b70e75 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.h +++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.h
@@ -1,4 +1,4 @@ -// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc index 581135e..547b28f 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc +++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc
@@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h index 4d84049..c914772 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h +++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h
@@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc b/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc index f683e4b..e7305716 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc +++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader.cc
@@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader.h b/chrome/browser/media/webrtc/webrtc_event_log_uploader.h index 61b3288..b40b3ad5 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_uploader.h +++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader.h
@@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc b/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc index e99ed88d..65e032d3 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc +++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc
@@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// 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.
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index 6f62c20..f2201ad 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -461,7 +461,7 @@ !base::FeatureList::IsEnabled(features::kExperimentalUi)) { return; // No need to even create the bridge if it's not going to be used. } - // If an accessory exists already, |CreateForWebContents| is a NoOp. + // If an accessory exists already, |CreateForWebContents| is a NoOp PasswordAccessoryController::CreateForWebContents(web_contents()); PasswordAccessoryController::FromWebContents(web_contents()) ->SavePasswordsForOrigin(best_matches, url::Origin::Create(origin)); @@ -561,7 +561,12 @@ web_contents()->GetRenderViewHost()->GetWidget()->RemoveInputEventObserver( this); web_contents()->GetRenderViewHost()->GetWidget()->AddInputEventObserver(this); -#endif +#else // defined(OS_ANDROID) + PasswordAccessoryController* accessory = + PasswordAccessoryController::FromWebContents(web_contents()); + if (accessory) + accessory->DidNavigateMainFrame(); +#endif // defined(OS_ANDROID) } #if !defined(OS_ANDROID) @@ -1078,16 +1083,17 @@ !base::FeatureList::IsEnabled(features::kExperimentalUi)) { return; // No need to even create the bridge if it's not going to be used. } - if (is_fillable) // Refresh but don't create a new accessory in this case. + if (is_fillable) { // If not fillable, update existing an accessory only. PasswordAccessoryController::CreateForWebContents(web_contents()); + } PasswordAccessoryController* accessory = PasswordAccessoryController::FromWebContents(web_contents()); - if (!accessory) - return; // No accessory needs change here. - accessory->RefreshSuggestionsForField( - password_manager_driver_bindings_.GetCurrentTargetFrame() - ->GetLastCommittedOrigin(), - is_fillable, is_password_field); + if (accessory) { + accessory->RefreshSuggestionsForField( + password_manager_driver_bindings_.GetCurrentTargetFrame() + ->GetLastCommittedOrigin(), + is_fillable, is_password_field); + } #endif // defined(OS_ANDROID) }
diff --git a/chrome/browser/password_manager/password_accessory_controller.cc b/chrome/browser/password_manager/password_accessory_controller.cc index 11d7906..df082bc 100644 --- a/chrome/browser/password_manager/password_accessory_controller.cc +++ b/chrome/browser/password_manager/password_accessory_controller.cc
@@ -6,14 +6,18 @@ #include <vector> +#include "base/callback.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/android/preferences/preferences_launcher.h" +#include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/password_manager/password_generation_dialog_view_interface.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" #include "chrome/grit/generated_resources.h" #include "components/autofill/content/browser/content_autofill_driver.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/common/password_form.h" +#include "components/favicon/core/favicon_service.h" #include "components/password_manager/content/browser/content_password_manager_driver.h" #include "components/password_manager/content/browser/content_password_manager_driver_factory.h" #include "components/password_manager/core/browser/password_manager_driver.h" @@ -65,22 +69,35 @@ Item::Type username_type; }; +struct PasswordAccessoryController::FaviconRequestData { + // List of requests waiting for favicons to be available. + std::vector<base::OnceCallback<void(const gfx::Image&)>> pending_requests; + + // Cached image for this origin. |IsEmpty()| unless a favicon was found. + gfx::Image cached_icon; +}; + PasswordAccessoryController::PasswordAccessoryController( content::WebContents* web_contents) : web_contents_(web_contents), view_(PasswordAccessoryViewInterface::Create(this)), create_dialog_factory_( base::BindRepeating(&PasswordGenerationDialogViewInterface::Create)), + favicon_service_(FaviconServiceFactory::GetForProfile( + Profile::FromBrowserContext(web_contents->GetBrowserContext()), + ServiceAccessType::EXPLICIT_ACCESS)), weak_factory_(this) {} // Additional creation functions in unit tests only: PasswordAccessoryController::PasswordAccessoryController( content::WebContents* web_contents, std::unique_ptr<PasswordAccessoryViewInterface> view, - CreateDialogFactory create_dialog_factory) + CreateDialogFactory create_dialog_factory, + favicon::FaviconService* favicon_service) : web_contents_(web_contents), view_(std::move(view)), create_dialog_factory_(create_dialog_factory), + favicon_service_(favicon_service), weak_factory_(this) {} PasswordAccessoryController::~PasswordAccessoryController() = default; @@ -89,13 +106,14 @@ void PasswordAccessoryController::CreateForWebContentsForTesting( content::WebContents* web_contents, std::unique_ptr<PasswordAccessoryViewInterface> view, - CreateDialogFactory create_dialog_factory) { + CreateDialogFactory create_dialog_factory, + favicon::FaviconService* favicon_service) { DCHECK(web_contents) << "Need valid WebContents to attach controller to!"; DCHECK(!FromWebContents(web_contents)) << "Controller already attached!"; web_contents->SetUserData( - UserDataKey(), - base::WrapUnique(new PasswordAccessoryController( - web_contents, std::move(view), create_dialog_factory))); + UserDataKey(), base::WrapUnique(new PasswordAccessoryController( + web_contents, std::move(view), create_dialog_factory, + favicon_service))); } void PasswordAccessoryController::SavePasswordsForOrigin( @@ -135,6 +153,67 @@ view_->OnAutomaticGenerationStatusChanged(available); } +void PasswordAccessoryController::OnFilledIntoFocusedField( + autofill::FillingStatus status) { + // TODO(crbug/853766): Record success rate. + // TODO(fhorschig): Update UI by hiding the sheet or communicating the error. +} + +void PasswordAccessoryController::RefreshSuggestionsForField( + const url::Origin& origin, + bool is_fillable, + bool is_password_field) { + // TODO(crbug/853766): Record CTR metric. + if (is_fillable) { + current_origin_ = origin; + view_->OnItemsAvailable(CreateViewItems(origin, origin_suggestions_[origin], + is_password_field)); + } else { + // For unfillable fields, reset the origin and send the empty state message. + current_origin_ = url::Origin(); + view_->OnItemsAvailable(CreateViewItems( + origin, std::vector<SuggestionElementData>(), is_password_field)); + } +} + +void PasswordAccessoryController::DidNavigateMainFrame() { + if (current_origin_.IsSameOriginWith( + web_contents_->GetMainFrame()->GetLastCommittedOrigin())) + return; // Clean requests only if the navigation was across origins. + favicon_tracker_.TryCancelAll(); // If there is a request pending, cancel it. + current_origin_ = url::Origin(); + icons_request_data_.clear(); + origin_suggestions_.clear(); +} + +void PasswordAccessoryController::GetFavicon( + base::OnceCallback<void(const gfx::Image&)> icon_callback) { + url::Origin origin = current_origin_; // Copy origin in case it changes. + // Check whether this request can be immediately answered with a cached icon. + // It is empty if there wasn't at least one request that found an icon yet. + FaviconRequestData* icon_request = &icons_request_data_[origin]; + if (!icon_request->cached_icon.IsEmpty()) { + std::move(icon_callback).Run(icon_request->cached_icon); + return; + } + if (!favicon_service_) { // This might happen in tests. + std::move(icon_callback).Run(gfx::Image()); + return; + } + + // The cache is empty. Queue the callback. + icon_request->pending_requests.emplace_back(std::move(icon_callback)); + if (icon_request->pending_requests.size() > 1) + return; // The favicon for this origin was already requested. + + favicon_service_->GetFaviconImageForPageURL( + origin.GetURL(), + base::BindRepeating( // FaviconService doesn't support BindOnce yet. + &PasswordAccessoryController::OnImageFetched, + weak_factory_.GetWeakPtr(), origin), + &favicon_tracker_); +} + void PasswordAccessoryController::OnFillingTriggered( bool is_password, const base::string16& textToFill) { @@ -200,24 +279,6 @@ chrome::android::PreferencesLauncher::ShowPasswordSettings(); } -void PasswordAccessoryController::OnFilledIntoFocusedField( - autofill::FillingStatus status) { - // TODO(crbug/853766): Record success rate. - // TODO(fhorschig): Update UI by hiding the sheet or communicating the error. -} - -void PasswordAccessoryController::RefreshSuggestionsForField( - const url::Origin& origin, - bool is_fillable, - bool is_password_field) { - // TODO(crbug/853766): Record CTR metric. - view_->OnItemsAvailable( - CreateViewItems(origin, - is_fillable ? origin_suggestions_[origin] - : std::vector<SuggestionElementData>(), - is_password_field)); -} - gfx::NativeView PasswordAccessoryController::container_view() const { return web_contents_->GetNativeView(); } @@ -268,3 +329,17 @@ Item::Type::OPTION); return items; } + +void PasswordAccessoryController::OnImageFetched( + url::Origin origin, + const favicon_base::FaviconImageResult& image_result) { + FaviconRequestData* icon_request = &icons_request_data_[origin]; + icon_request->cached_icon = image_result.image; + // Only trigger all the callbacks if they still affect a displayed origin. + if (origin == current_origin_) { + for (auto& callback : icon_request->pending_requests) { + std::move(callback).Run(icon_request->cached_icon); + } + } + icon_request->pending_requests.clear(); +}
diff --git a/chrome/browser/password_manager/password_accessory_controller.h b/chrome/browser/password_manager/password_accessory_controller.h index 2231d353..4121bf9c4 100644 --- a/chrome/browser/password_manager/password_accessory_controller.h +++ b/chrome/browser/password_manager/password_accessory_controller.h
@@ -10,13 +10,16 @@ #include <utility> #include <vector> -#include "base/callback.h" +#include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" +#include "base/task/cancelable_task_tracker.h" #include "chrome/browser/password_manager/password_accessory_view_interface.h" #include "components/autofill/core/common/filling_status.h" #include "components/autofill/core/common/password_generation_util.h" +#include "components/favicon_base/favicon_types.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/web_contents_user_data.h" #include "ui/gfx/native_widget_types.h" #include "url/gurl.h" @@ -25,6 +28,10 @@ struct PasswordForm; } // namespace autofill +namespace favicon { +class FaviconService; +} + namespace password_manager { class PasswordManagerDriver; } // namespace password_manager @@ -52,6 +59,10 @@ PasswordGenerationDialogViewInterface>(PasswordAccessoryController*)>; ~PasswordAccessoryController() override; + // ----------------------------- + // Methods called by the client: + // ----------------------------- + // Saves credentials for an origin so that they can be used in the sheet. void SavePasswordsForOrigin( const std::map<base::string16, const autofill::PasswordForm*>& @@ -65,6 +76,30 @@ autofill::password_generation::PasswordGenerationUIData>& ui_data, const base::WeakPtr<password_manager::PasswordManagerDriver>& driver); + // Completes a filling attempt by recording metrics, giving feedback to the + // user and dismissing the accessory sheet. + void OnFilledIntoFocusedField(autofill::FillingStatus status); + + // Makes sure, that all shown suggestions are appropriate for the currently + // focused field and for fields that lost the focus. If a field lost focus, + // |is_fillable| will be false. + void RefreshSuggestionsForField(const url::Origin& origin, + bool is_fillable, + bool is_password_field); + + // Reacts to a navigation on the main frame, e.g. by clearing caches. + void DidNavigateMainFrame(); + + // -------------------------- + // Methods called by UI code: + // -------------------------- + + // Uses the give |favicon_service| to get an icon for the currently focused + // frame. The given callback is called with an image unless an icon for a new + // origin was called. In the latter case, the callback is dropped. + // The callback is called with an |IsEmpty()| image if there is no favicon. + void GetFavicon(base::OnceCallback<void(const gfx::Image&)> icon_callback); + // Called by the UI code to request that |textToFill| is to be filled into the // currently focused field. void OnFillingTriggered(bool is_password, const base::string16& textToFill); @@ -86,16 +121,9 @@ // in the explanation text that leads to the saved passwords. void OnSavedPasswordsLinkClicked(); - // Compeletes a filling attempt by recording metrics, giving feedback to the - // user and dismissing the accessory sheet. - void OnFilledIntoFocusedField(autofill::FillingStatus status); - - // Makes sure, that all shown suggestions are appropriate for the currently - // focused field and for fields that lost the focus. If a field lost focus, - // |is_fillable| will be false. - void RefreshSuggestionsForField(const url::Origin& origin, - bool is_fillable, - bool is_password_field); + // ----------------- + // Member accessors: + // ----------------- // The web page view containing the focused field. gfx::NativeView container_view() const; @@ -107,7 +135,8 @@ static void CreateForWebContentsForTesting( content::WebContents* web_contents, std::unique_ptr<PasswordAccessoryViewInterface> test_view, - CreateDialogFactory create_dialog_callback); + CreateDialogFactory create_dialog_callback, + favicon::FaviconService* favicon_service); #if defined(UNIT_TEST) // Returns the held view for testing. @@ -122,6 +151,9 @@ // Data for a credential pair that is transformed into a suggestion. struct SuggestionElementData; + // Data allowing to cache favicons and favicon-related requests. + struct FaviconRequestData; + // Required for construction via |CreateForWebContents|: explicit PasswordAccessoryController(content::WebContents* contents); friend class content::WebContentsUserData<PasswordAccessoryController>; @@ -130,7 +162,8 @@ PasswordAccessoryController( content::WebContents* web_contents, std::unique_ptr<PasswordAccessoryViewInterface> view, - CreateDialogFactory create_dialog_callback); + CreateDialogFactory create_dialog_callback, + favicon::FaviconService* favicon_service); // Creates the view items based on the given |suggestions|. // If |is_password_field| is false, password suggestions won't be interactive. @@ -139,6 +172,11 @@ const std::vector<SuggestionElementData>& suggestions, bool is_password_field); + // Handles a favicon response requested by |GetFavicon| and calls the waiting + // last_icon_callback_ with a (possibly empty) icon bitmap. + void OnImageFetched(url::Origin origin, + const favicon_base::FaviconImageResult& image_result); + // Contains the last set of credentials by origin. std::map<url::Origin, std::vector<SuggestionElementData>> origin_suggestions_; @@ -148,6 +186,19 @@ // Data for the generation element used to generate the password. std::unique_ptr<GenerationElementData> generation_element_data_; + // The origin of the currently focused frame. It's used to ensure that + // favicons are not displayed across origins. + url::Origin current_origin_; + + // TODO(fhorschig): Find a way to use unordered_map with origin keys. + // A cache for all favicons that were requested. This includes all iframes + // for which the accessory was displayed. + std::map<url::Origin, FaviconRequestData> icons_request_data_; + + // Used to track a requested favicon. If the set of suggestion changes, this + // object aborts the request. Upon destruction, requests are cancelled, too. + base::CancelableTaskTracker favicon_tracker_; + // Password manager driver for the target frame used for password generation. base::WeakPtr<password_manager::PasswordManagerDriver> target_frame_driver_; @@ -166,6 +217,9 @@ // Creation callback for the modal dialog view meant to facilitate testing. CreateDialogFactory create_dialog_factory_; + // The favicon service used to make retrieve icons for a given origin. + favicon::FaviconService* favicon_service_; + base::WeakPtrFactory<PasswordAccessoryController> weak_factory_; DISALLOW_COPY_AND_ASSIGN(PasswordAccessoryController);
diff --git a/chrome/browser/password_manager/password_accessory_controller_unittest.cc b/chrome/browser/password_manager/password_accessory_controller_unittest.cc index c5603a5..a92c1b92 100644 --- a/chrome/browser/password_manager/password_accessory_controller_unittest.cc +++ b/chrome/browser/password_manager/password_accessory_controller_unittest.cc
@@ -8,11 +8,13 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/test/mock_callback.h" +#include "base/test/scoped_task_environment.h" #include "chrome/browser/password_manager/password_accessory_view_interface.h" #include "chrome/browser/password_manager/password_generation_dialog_view_interface.h" #include "chrome/grit/generated_resources.h" @@ -20,12 +22,14 @@ #include "components/autofill/core/common/password_form.h" #include "components/autofill/core/common/password_generation_util.h" #include "components/autofill/core/common/signatures_util.h" +#include "components/favicon/core/test/mock_favicon_service.h" #include "components/password_manager/core/browser/password_generation_manager.h" #include "components/password_manager/core/browser/stub_password_manager_client.h" #include "components/password_manager/core/browser/stub_password_manager_driver.h" #include "components/strings/grit/components_strings.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/l10n/l10n_util.h" namespace { @@ -237,14 +241,19 @@ class PasswordAccessoryControllerTest : public ChromeRenderViewHostTestHarness { public: + PasswordAccessoryControllerTest() + : mock_favicon_service_( + std::make_unique< + testing::StrictMock<favicon::MockFaviconService>>()) {} + void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); NavigateAndCommit(GURL(kExampleSite)); PasswordAccessoryController::CreateForWebContentsForTesting( web_contents(), std::make_unique<StrictMock<MockPasswordAccessoryView>>(), - mock_dialog_factory_.Get()); - NavigateAndCommit(GURL("https://example.com")); + mock_dialog_factory_.Get(), favicon_service()); + NavigateAndCommit(GURL(kExampleSite)); } PasswordAccessoryController* controller() { @@ -260,9 +269,15 @@ return mock_dialog_factory_; } + favicon::MockFaviconService* favicon_service() { + return mock_favicon_service_.get(); + } + private: base::MockCallback<PasswordAccessoryController::CreateDialogFactory> mock_dialog_factory_; + std::unique_ptr<testing::StrictMock<favicon::MockFaviconService>> + mock_favicon_service_; }; TEST_F(PasswordAccessoryControllerTest, IsNotRecreatedForSameWebContents) { @@ -275,6 +290,9 @@ } TEST_F(PasswordAccessoryControllerTest, TransformsMatchesToSuggestions) { + controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, + url::Origin::Create(GURL(kExampleSite))); + EXPECT_CALL(*view(), OnItemsAvailable(ElementsAre( MatchesLabel(passwords_title_str(kExampleDomain)), @@ -283,9 +301,6 @@ MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); - - controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, - url::Origin::Create(GURL(kExampleSite))); controller()->RefreshSuggestionsForField( url::Origin::Create(GURL(kExampleSite)), /*is_fillable=*/true, @@ -293,6 +308,9 @@ } TEST_F(PasswordAccessoryControllerTest, HintsToEmptyUserNames) { + controller()->SavePasswordsForOrigin({CreateEntry("", "S3cur3").first}, + url::Origin::Create(GURL(kExampleSite))); + EXPECT_CALL( *view(), OnItemsAvailable(ElementsAre( @@ -302,9 +320,6 @@ MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str(no_user_str()), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); - - controller()->SavePasswordsForOrigin({CreateEntry("", "S3cur3").first}, - url::Origin::Create(GURL(kExampleSite))); controller()->RefreshSuggestionsForField( url::Origin::Create(GURL(kExampleSite)), /*is_fillable=*/true, @@ -312,6 +327,11 @@ } TEST_F(PasswordAccessoryControllerTest, SortsAlphabeticalDuringTransform) { + controller()->SavePasswordsForOrigin( + {CreateEntry("Ben", "S3cur3").first, CreateEntry("Zebra", "M3h").first, + CreateEntry("Alf", "PWD").first, CreateEntry("Cat", "M1@u").first}, + url::Origin::Create(GURL(kExampleSite))); + EXPECT_CALL(*view(), OnItemsAvailable(ElementsAre( MatchesLabel(passwords_title_str(kExampleDomain)), @@ -336,11 +356,6 @@ MatchesItem(ASCIIToUTF16("M3h"), password_for_str("Zebra"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); - - controller()->SavePasswordsForOrigin( - {CreateEntry("Ben", "S3cur3").first, CreateEntry("Zebra", "M3h").first, - CreateEntry("Alf", "PWD").first, CreateEntry("Cat", "M1@u").first}, - url::Origin::Create(GURL(kExampleSite))); controller()->RefreshSuggestionsForField( url::Origin::Create(GURL(kExampleSite)), /*is_fillable=*/true, @@ -348,6 +363,10 @@ } TEST_F(PasswordAccessoryControllerTest, RepeatsSuggestionsForSameFrame) { + controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, + url::Origin::Create(GURL(kExampleSite))); + + // Pretend that any input in the same frame was focused. EXPECT_CALL(*view(), OnItemsAvailable(ElementsAre( MatchesLabel(passwords_title_str(kExampleDomain)), @@ -356,12 +375,6 @@ MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); - - // Set any, non-empty password list. - controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, - url::Origin::Create(GURL(kExampleSite))); - - // Pretend that any input in the same frame was focused. controller()->RefreshSuggestionsForField( url::Origin::Create(GURL(kExampleSite)), /*is_fillable=*/true, @@ -369,14 +382,14 @@ } TEST_F(PasswordAccessoryControllerTest, ProvidesEmptySuggestionsMessage) { + controller()->SavePasswordsForOrigin({}, + url::Origin::Create(GURL(kExampleSite))); + EXPECT_CALL( *view(), OnItemsAvailable( ElementsAre(MatchesLabel(passwords_empty_str(kExampleDomain)), IsDivider(), MatchesOption(manage_passwords_str())))); - - controller()->SavePasswordsForOrigin({}, - url::Origin::Create(GURL(kExampleSite))); controller()->RefreshSuggestionsForField( url::Origin::Create(GURL(kExampleSite)), /*is_fillable=*/true, @@ -436,6 +449,10 @@ } TEST_F(PasswordAccessoryControllerTest, PasswordFieldChangesSuggestionType) { + controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, + url::Origin::Create(GURL(kExampleSite))); + // Pretend a username field was focused. This should result in non-interactive + // suggestion. EXPECT_CALL(*view(), OnItemsAvailable(ElementsAre( MatchesLabel(passwords_title_str(kExampleDomain)), @@ -444,10 +461,6 @@ MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); - // Set any, non-empty password list and pretend a username field was focused. - // This should result in the non-interactive suggestion expected above. - controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, - url::Origin::Create(GURL(kExampleSite))); controller()->RefreshSuggestionsForField( url::Origin::Create(GURL(kExampleSite)), /*is_fillable=*/true, @@ -470,6 +483,8 @@ } TEST_F(PasswordAccessoryControllerTest, CachesIsReplacedByNewPasswords) { + controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, + url::Origin::Create(GURL(kExampleSite))); EXPECT_CALL(*view(), OnItemsAvailable(ElementsAre( MatchesLabel(passwords_title_str(kExampleDomain)), @@ -478,13 +493,13 @@ MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); - controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, - url::Origin::Create(GURL(kExampleSite))); controller()->RefreshSuggestionsForField( url::Origin::Create(GURL(kExampleSite)), /*is_fillable=*/true, /*is_password_field=*/false); + controller()->SavePasswordsForOrigin({CreateEntry("Alf", "M3lm4k").first}, + url::Origin::Create(GURL(kExampleSite))); EXPECT_CALL(*view(), OnItemsAvailable(ElementsAre( MatchesLabel(passwords_title_str(kExampleDomain)), @@ -493,8 +508,6 @@ MatchesItem(ASCIIToUTF16("M3lm4k"), password_for_str("Alf"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); - controller()->SavePasswordsForOrigin({CreateEntry("Alf", "M3lm4k").first}, - url::Origin::Create(GURL(kExampleSite))); controller()->RefreshSuggestionsForField( url::Origin::Create(GURL(kExampleSite)), /*is_fillable=*/true, @@ -502,6 +515,10 @@ } TEST_F(PasswordAccessoryControllerTest, UnfillableFieldClearsSuggestions) { + controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, + url::Origin::Create(GURL(kExampleSite))); + // Pretend a username field was focused. This should result in non-emtpy + // suggestions. EXPECT_CALL(*view(), OnItemsAvailable(ElementsAre( MatchesLabel(passwords_title_str(kExampleDomain)), @@ -510,10 +527,6 @@ MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); - // Set any, non-empty password list and pretend a username field was focused. - // This should result in the non-emtpy suggestions expected above. - controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, - url::Origin::Create(GURL(kExampleSite))); controller()->RefreshSuggestionsForField( url::Origin::Create(GURL(kExampleSite)), /*is_fillable=*/true, @@ -530,3 +543,147 @@ /*is_fillable=*/false, /*is_password_field=*/false); // Unused. } + +TEST_F(PasswordAccessoryControllerTest, NavigatingMainFrameClearsSuggestions) { + // Set any, non-empty password list and pretend a username field was focused. + // This should result in non-emtpy suggestions. + controller()->SavePasswordsForOrigin({CreateEntry("Ben", "S3cur3").first}, + url::Origin::Create(GURL(kExampleSite))); + EXPECT_CALL(*view(), + OnItemsAvailable(ElementsAre( + MatchesLabel(passwords_title_str(kExampleDomain)), + MatchesItem(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, + ItemType::SUGGESTION), + MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), + true, ItemType::NON_INTERACTIVE_SUGGESTION), + IsDivider(), MatchesOption(manage_passwords_str())))); + controller()->RefreshSuggestionsForField( + url::Origin::Create(GURL(kExampleSite)), + /*is_fillable=*/true, + /*is_password_field=*/false); + + // Pretend that the focus was lost or moved to an unfillable field. + NavigateAndCommit(GURL("https://random.other-site.org/")); + controller()->DidNavigateMainFrame(); + + // Now, only the empty state message should be sent. + EXPECT_CALL(*view(), + OnItemsAvailable(ElementsAre( + MatchesLabel(passwords_empty_str("random.other-site.org")), + IsDivider(), MatchesOption(manage_passwords_str())))); + controller()->RefreshSuggestionsForField( + url::Origin::Create(GURL("https://random.other-site.org/")), + /*is_fillable=*/true, + /*is_password_field=*/false); // Unused. +} + +TEST_F(PasswordAccessoryControllerTest, FetchFaviconForCurrentUrl) { + base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback; + + EXPECT_CALL(*view(), OnItemsAvailable(_)); + controller()->RefreshSuggestionsForField( + url::Origin::Create(GURL(kExampleSite)), + /*is_fillable=*/true, + /*is_password_field=*/false); + + EXPECT_CALL(*favicon_service(), + GetFaviconImageForPageURL(GURL(kExampleSite), _, _)) + .WillOnce(favicon::PostReply<3>(favicon_base::FaviconImageResult())); + EXPECT_CALL(mock_callback, Run); + controller()->GetFavicon(mock_callback.Get()); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(PasswordAccessoryControllerTest, RequestsFaviconsOnceForOneOrigin) { + base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback; + + EXPECT_CALL(*view(), OnItemsAvailable(_)); + controller()->RefreshSuggestionsForField( + url::Origin::Create(GURL(kExampleSite)), + /*is_fillable=*/true, + /*is_password_field=*/false); + + EXPECT_CALL(*favicon_service(), + GetFaviconImageForPageURL(GURL(kExampleSite), _, _)) + .WillOnce(favicon::PostReply<3>(favicon_base::FaviconImageResult())); + EXPECT_CALL(mock_callback, Run).Times(2); + controller()->GetFavicon(mock_callback.Get()); + // The favicon service should already start to work on the request. + Mock::VerifyAndClearExpectations(favicon_service()); + + // This call is only enqueued (and the callback will be called afterwards). + controller()->GetFavicon(mock_callback.Get()); + + // After the async task is finished, both callbacks must be called. + base::RunLoop().RunUntilIdle(); +} + +TEST_F(PasswordAccessoryControllerTest, FaviconsAreCachedUntilNavigation) { + base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback; + + // We need a result with a non-empty image or it won't get cached. + favicon_base::FaviconImageResult non_empty_result; + SkBitmap bitmap; + bitmap.allocN32Pixels(32, 32); + non_empty_result.image = gfx::Image::CreateFrom1xBitmap(bitmap); + + // Populate the cache by requesting a favicon. + EXPECT_CALL(*view(), OnItemsAvailable(_)); + controller()->RefreshSuggestionsForField( + url::Origin::Create(GURL(kExampleSite)), + /*is_fillable=*/true, + /*is_password_field=*/false); + + EXPECT_CALL(*favicon_service(), + GetFaviconImageForPageURL(GURL(kExampleSite), _, _)) + .WillOnce(favicon::PostReply<3>(non_empty_result)); + EXPECT_CALL(mock_callback, Run).Times(1); + controller()->GetFavicon(mock_callback.Get()); + + base::RunLoop().RunUntilIdle(); + Mock::VerifyAndClearExpectations(&mock_callback); + + // This call is handled by the cache - no favicon service, no async request. + EXPECT_CALL(mock_callback, Run).Times(1); + controller()->GetFavicon(mock_callback.Get()); + Mock::VerifyAndClearExpectations(&mock_callback); + Mock::VerifyAndClearExpectations(favicon_service()); + + // The navigation to another origin clears the cache. + NavigateAndCommit(GURL("https://random.other-site.org/")); + controller()->DidNavigateMainFrame(); + NavigateAndCommit(GURL(kExampleSite)); // Same origin as intially. + controller()->DidNavigateMainFrame(); + EXPECT_CALL(*view(), OnItemsAvailable(_)); + controller()->RefreshSuggestionsForField( + url::Origin::Create(GURL(kExampleSite)), true, false); + + // The cache was cleared, so now the service has to be queried again. + EXPECT_CALL(*favicon_service(), + GetFaviconImageForPageURL(GURL(kExampleSite), _, _)) + .WillOnce(favicon::PostReply<3>(non_empty_result)); + EXPECT_CALL(mock_callback, Run).Times(1); + controller()->GetFavicon(mock_callback.Get()); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(PasswordAccessoryControllerTest, NoFaviconCallbacksWhenOriginChanges) { + base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback; + + EXPECT_CALL(*view(), OnItemsAvailable(_)).Times(2); + controller()->RefreshSuggestionsForField( + url::Origin::Create(GURL(kExampleSite)), true, false); + + // Right after starting the favicon request for example.com, another frame on + // the same site is focused. Even if the request is completed, the callback + // should not be called because the origin of the suggestions has changed. + EXPECT_CALL(*favicon_service(), + GetFaviconImageForPageURL(GURL(kExampleSite), _, _)) + .WillOnce(favicon::PostReply<3>(favicon_base::FaviconImageResult())); + EXPECT_CALL(mock_callback, Run).Times(0); + controller()->GetFavicon(mock_callback.Get()); + controller()->RefreshSuggestionsForField( + url::Origin::Create(GURL("https://other.frame.com/")), true, false); + + base::RunLoop().RunUntilIdle(); +}
diff --git a/chrome/browser/policy/browser_dm_token_storage_mac.mm b/chrome/browser/policy/browser_dm_token_storage_mac.mm index f0fd5a67..68fa61c8 100644 --- a/chrome/browser/policy/browser_dm_token_storage_mac.mm +++ b/chrome/browser/policy/browser_dm_token_storage_mac.mm
@@ -16,7 +16,6 @@ #include "base/mac/foundation_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_ioobject.h" -#import "base/mac/scoped_nsautorelease_pool.h" #include "base/no_destructor.h" #include "base/path_service.h" #include "base/sha1.h" @@ -37,8 +36,8 @@ const char kDmTokenBaseDir[] = FILE_PATH_LITERAL("Google/Chrome Cloud Enrollment/"); -NSString* const kEnrollmentTokenPolicyName = - @"MachineLevelUserCloudPolicyEnrollmentToken"; +const CFStringRef kEnrollmentTokenPolicyName = + CFSTR("MachineLevelUserCloudPolicyEnrollmentToken"); bool GetDmTokenFilePath(base::FilePath* token_file_path, const std::string& client_id, @@ -111,16 +110,29 @@ } std::string BrowserDMTokenStorageMac::InitEnrollmentToken() { - base::mac::ScopedNSAutoreleasePool pool; - // Since the configuration management infrastructure is not initialized when // this code runs, read the policy preference directly. - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - NSString* value = [defaults stringForKey:kEnrollmentTokenPolicyName]; - if (value && [defaults objectIsForcedForKey:kEnrollmentTokenPolicyName]) - return base::SysNSStringToUTF8(value); - else +#if defined(GOOGLE_CHROME_BUILD) + // Explicitly access the "com.google.Chrome" bundle ID, no matter what this + // app's bundle ID actually is. All channels of Chrome should obey the same + // policies. + CFStringRef bundle_id = CFSTR("com.google.Chrome"); +#else + base::ScopedCFTypeRef<CFStringRef> bundle_id( + base::SysUTF8ToCFStringRef(base::mac::BaseBundleID())); +#endif + + base::ScopedCFTypeRef<CFPropertyListRef> value( + CFPreferencesCopyAppValue(kEnrollmentTokenPolicyName, bundle_id)); + + if (!value || + !CFPreferencesAppValueIsForced(kEnrollmentTokenPolicyName, bundle_id)) return std::string(); + CFStringRef value_string = base::mac::CFCast<CFStringRef>(value); + if (!value_string) + return std::string(); + + return base::SysCFStringRefToUTF8(value_string); } std::string BrowserDMTokenStorageMac::InitDMToken() {
diff --git a/chrome/browser/policy/policy_path_parser_mac.mm b/chrome/browser/policy/policy_path_parser_mac.mm index 92e32e4..eb093e8 100644 --- a/chrome/browser/policy/policy_path_parser_mac.mm +++ b/chrome/browser/policy/policy_path_parser_mac.mm
@@ -14,7 +14,8 @@ #include "base/files/file_path.h" #include "base/logging.h" -#import "base/mac/scoped_nsautorelease_pool.h" +#include "base/mac/foundation_util.h" +#include "base/mac/scoped_cftyperef.h" #include "base/macros.h" #include "base/strings/sys_string_conversions.h" #include "components/policy/policy_constants.h" @@ -28,16 +29,15 @@ const char kMacUsersDirectory[] = "${users}"; const char kMacDocumentsFolderVarName[] = "${documents}"; -struct MacFolderNamesToSPDMaping { +struct MacFolderNamesToSPDMapping { const char* name; NSSearchPathDirectory id; }; // Mapping from variable names to MacOS NSSearchPathDirectory ids. -const MacFolderNamesToSPDMaping mac_folder_mapping[] = { - { kMacUsersDirectory, NSUserDirectory}, - { kMacDocumentsFolderVarName, NSDocumentDirectory} -}; +const MacFolderNamesToSPDMapping mac_folder_mapping[] = { + {kMacUsersDirectory, NSUserDirectory}, + {kMacDocumentsFolderVarName, NSDocumentDirectory}}; // Replaces all variable occurrences in the policy string with the respective // system settings values. @@ -54,14 +54,14 @@ result = result.substr(1, result.length() - 2); } // First translate all path variables we recognize. - for (size_t i = 0; i < arraysize(mac_folder_mapping); ++i) { - size_t position = result.find(mac_folder_mapping[i].name); + for (const auto& mapping : mac_folder_mapping) { + size_t position = result.find(mapping.name); if (position != std::string::npos) { NSArray* searchpaths = NSSearchPathForDirectoriesInDomains( - mac_folder_mapping[i].id, NSAllDomainsMask, true); + mapping.id, NSAllDomainsMask, true); if ([searchpaths count] > 0) { NSString *variable_value = [searchpaths objectAtIndex:0]; - result.replace(position, strlen(mac_folder_mapping[i].name), + result.replace(position, strlen(mapping.name), base::SysNSStringToUTF8(variable_value)); } } @@ -79,39 +79,51 @@ } position = result.find(kMachineNamePolicyVarName); if (position != std::string::npos) { - SCDynamicStoreContext context = { 0, NULL, NULL, NULL }; - SCDynamicStoreRef store = SCDynamicStoreCreate(kCFAllocatorDefault, - CFSTR("policy_subsystem"), - NULL, &context); - CFStringRef machinename = SCDynamicStoreCopyLocalHostName(store); + SCDynamicStoreContext context = {0, nullptr, nullptr, nullptr}; + base::ScopedCFTypeRef<SCDynamicStoreRef> store(SCDynamicStoreCreate( + kCFAllocatorDefault, CFSTR("policy_subsystem"), nullptr, &context)); + base::ScopedCFTypeRef<CFStringRef> machinename( + SCDynamicStoreCopyLocalHostName(store)); if (machinename) { result.replace(position, strlen(kMachineNamePolicyVarName), base::SysCFStringRefToUTF8(machinename)); - CFRelease(machinename); } else { int error = SCError(); LOG(ERROR) << "Machine name variable can not be resolved. Error: " << error << " - " << SCErrorString(error); } - CFRelease(store); } return result; } void CheckUserDataDirPolicy(base::FilePath* user_data_dir) { - base::mac::ScopedNSAutoreleasePool pool; - // Since the configuration management infrastructure is not initialized when // this code runs, read the policy preference directly. - NSString* key = base::SysUTF8ToNSString(policy::key::kUserDataDir); - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - NSString* value = [defaults stringForKey:key]; - if (value && [defaults objectIsForcedForKey:key]) { - std::string string_value = base::SysNSStringToUTF8(value); - // Now replace any vars the user might have used. - string_value = policy::path_parser::ExpandPathVariables(string_value); - *user_data_dir = base::FilePath(string_value); - } +#if defined(GOOGLE_CHROME_BUILD) + // Explicitly access the "com.google.Chrome" bundle ID, no matter what this + // app's bundle ID actually is. All channels of Chrome should obey the same + // policies. + CFStringRef bundle_id = CFSTR("com.google.Chrome"); +#else + base::ScopedCFTypeRef<CFStringRef> bundle_id( + base::SysUTF8ToCFStringRef(base::mac::BaseBundleID())); +#endif + + base::ScopedCFTypeRef<CFStringRef> key( + base::SysUTF8ToCFStringRef(policy::key::kUserDataDir)); + base::ScopedCFTypeRef<CFPropertyListRef> value( + CFPreferencesCopyAppValue(key, bundle_id)); + + if (!value || !CFPreferencesAppValueIsForced(key, bundle_id)) + return; + CFStringRef value_string = base::mac::CFCast<CFStringRef>(value); + if (!value_string) + return; + + // Now replace any vars the user might have used. + std::string string_value = base::SysCFStringRefToUTF8(value_string); + string_value = policy::path_parser::ExpandPathVariables(string_value); + *user_data_dir = base::FilePath(string_value); } void CheckDiskCacheDirPolicy(base::FilePath* user_data_dir) {
diff --git a/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc b/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc index c06ff41..5c8bdc8c 100644 --- a/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc +++ b/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc
@@ -10,6 +10,8 @@ #include "build/build_config.h" #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" @@ -639,6 +641,41 @@ reset_state_observer.Wait(); } +#if defined(USE_AURA) +// This test creates a blank page and adds an <input> to it. Then, the <input> +// is focused, UI is focused, then the input is refocused. The test verifies +// that selection bounds change with the refocus (see https://crbug.com/864563). +IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest, + SelectionBoundsChangeAfterRefocusInput) { + CreateIframePage("a()"); + content::RenderFrameHost* main_frame = GetFrame(IndexVector{}); + content::RenderWidgetHostView* view = main_frame->GetView(); + content::WebContents* web_contents = active_contents(); + AddInputFieldToFrame(main_frame, "text", "", false); + + auto focus_input_and_wait_for_selection_bounds_change = + [&main_frame, &web_contents, &view]() { + ViewSelectionBoundsChangedObserver bounds_observer(web_contents, view); + // SimulateKeyPress(web_contents, ui::DomKey::TAB, ui::DomCode::TAB, + // ui::VKEY_TAB, false, true, false, false); + EXPECT_TRUE(ExecuteScript(main_frame, + "document.querySelector('input').focus();")); + bounds_observer.Wait(); + }; + + focus_input_and_wait_for_selection_bounds_change(); + + // Focus location bar. + BrowserWindow* window = browser()->window(); + ASSERT_TRUE(window); + LocationBar* location_bar = window->GetLocationBar(); + ASSERT_TRUE(location_bar); + location_bar->FocusLocation(true); + + focus_input_and_wait_for_selection_bounds_change(); +} +#endif + // This test verifies that if we have a focused <input> in the main frame and // the tab is closed, TextInputManager handles unregistering itself and // notifying the observers properly (see https://crbug.com/669375).
diff --git a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc index 015a61e..6bb8317d 100644 --- a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc +++ b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h" +#include <limits> #include <string> #include "base/files/file_util.h" @@ -11,6 +12,7 @@ #include "base/memory/ptr_util.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/strings/string_number_conversions.h" #include "base/task_runner_util.h" #include "base/threading/thread_restrictions.h" #include "chrome/browser/resource_coordinator/utils.h" @@ -84,6 +86,23 @@ } // namespace +// Version history: +// +// - {no version}: +// - Initial launch of the Database. +// - 1: +// - Ignore the title/favicon events happening during the first fews seconds +// after a tab being loaded. +// - Ignore the audio events happening during the first fews seconds after a +// tab being backgrounded. +// +// Transform logic: +// - From {no version} to v1: The database is erased entirely. +const size_t LevelDBSiteCharacteristicsDatabase::kDbVersion = 1U; + +const char LevelDBSiteCharacteristicsDatabase::kDbMetadataKey[] = + "database_metadata"; + // Helper class used to run all the blocking operations posted by // LocalSiteCharacteristicDatabase on a TaskScheduler sequence with the // |MayBlock()| trait. @@ -102,7 +121,8 @@ } ~AsyncHelper() = default; - // Open the database from |db_path_| after creating it if it didn't exist. + // Open the database from |db_path_| after creating it if it didn't exist, + // this reset the database if it's not at the expected version. void OpenOrCreateDatabase(); // Implementations of the DB manipulation functions of @@ -118,7 +138,22 @@ bool DBIsInitialized() { return db_ != nullptr; } + leveldb::DB* GetDBForTesting() { + DCHECK(DBIsInitialized()); + return db_.get(); + } + private: + enum class OpeningType { + // A new database has been created. + kNewDb, + // An existing database has been used. + kExistingDb, + }; + + // Implementation for the OpenOrCreateDatabase function. + OpeningType OpenOrCreateDatabaseImpl(); + // The on disk location of the database. const base::FilePath db_path_; // The connection to the LevelDB database. @@ -133,43 +168,42 @@ }; void LevelDBSiteCharacteristicsDatabase::AsyncHelper::OpenOrCreateDatabase() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!db_) << "Database already open"; - base::AssertBlockingAllowed(); - - // Report the on disk size of the database if it already exists. - if (base::DirectoryExists(db_path_)) { - int64_t db_ondisk_size_in_bytes = base::ComputeDirectorySize(db_path_); - UMA_HISTOGRAM_MEMORY_KB("ResourceCoordinator.LocalDB.OnDiskSize", - db_ondisk_size_in_bytes / 1024); + OpeningType opening_type = OpenOrCreateDatabaseImpl(); + if (!db_) + return; + std::string db_metadata; + leveldb::Status s = db_->Get( + read_options_, LevelDBSiteCharacteristicsDatabase::kDbMetadataKey, + &db_metadata); + bool is_expected_version = false; + if (s.ok()) { + // The metadata only contains the version of the database as a size_t value + // for now. + size_t version = std::numeric_limits<size_t>::max(); + CHECK(base::StringToSizeT(db_metadata, &version)); + if (version == LevelDBSiteCharacteristicsDatabase::kDbVersion) + is_expected_version = true; } - - leveldb_env::Options options; - options.create_if_missing = true; - leveldb::Status status = - leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_); - - ReportInitStatus(kInitStatusHistogramLabel, status); - - if (status.ok()) - return; - - if (!ShouldAttemptDbRepair(status)) - return; - - if (RepairDatabase(db_path_.AsUTF8Unsafe())) { - status = leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_); - ReportInitStatus(kInitStatusAfterRepairHistogramLabel, status); - if (status.ok()) + // TODO(sebmarchand): Add a migration engine rather than flushing the database + // for every version change, https://crbug.com/866540. + if ((opening_type == OpeningType::kExistingDb) && !is_expected_version) { + DLOG(ERROR) << "Invalid DB version, recreating it."; + ClearDatabase(); + // The database might fail to open. + if (!db_) return; + opening_type = OpeningType::kNewDb; } - - // Delete the database and try to open it one last time. - if (leveldb_chrome::DeleteDB(db_path_, options).ok()) { - status = leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_); - ReportInitStatus(kInitStatusAfterDeleteHistogramLabel, status); - if (!status.ok()) - db_.reset(); + if (opening_type == OpeningType::kNewDb) { + std::string metadata = + base::NumberToString(LevelDBSiteCharacteristicsDatabase::kDbVersion); + s = db_->Put(write_options_, + LevelDBSiteCharacteristicsDatabase::kDbMetadataKey, + metadata); + if (!s.ok()) { + DLOG(ERROR) << "Error while inserting the metadata in the site " + << "characteristics database: " << s.ToString(); + } } } @@ -190,8 +224,8 @@ site_characteristic_proto = SiteCharacteristicsProto(); if (!site_characteristic_proto->ParseFromString(protobuf_value)) { site_characteristic_proto = base::nullopt; - LOG(ERROR) << "Error while trying to parse a SiteCharacteristicsProto " - << "protobuf."; + DLOG(ERROR) << "Error while trying to parse a SiteCharacteristicsProto " + << "protobuf."; } } return site_characteristic_proto; @@ -211,8 +245,9 @@ db_->Put(write_options_, SerializeOriginIntoDatabaseKey(origin), site_characteristic_proto.SerializeAsString()); if (!s.ok()) { - LOG(ERROR) << "Error while inserting an element in the site characteristic " - << "database: " << s.ToString(); + DLOG(ERROR) + << "Error while inserting an element in the site characteristics " + << "database: " << s.ToString(); } } @@ -245,13 +280,60 @@ db_.reset(); leveldb::Status status = leveldb::DestroyDB(db_path_.AsUTF8Unsafe(), options); if (status.ok()) { - OpenOrCreateDatabase(); + OpenOrCreateDatabaseImpl(); } else { LOG(WARNING) << "Failed to destroy the site characteristics database: " << status.ToString(); } } +LevelDBSiteCharacteristicsDatabase::AsyncHelper::OpeningType +LevelDBSiteCharacteristicsDatabase::AsyncHelper::OpenOrCreateDatabaseImpl() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!db_) << "Database already open"; + base::AssertBlockingAllowed(); + + OpeningType opening_type = OpeningType::kNewDb; + + // Report the on disk size of the database if it already exists. + if (base::DirectoryExists(db_path_)) { + opening_type = OpeningType::kExistingDb; + int64_t db_ondisk_size_in_bytes = base::ComputeDirectorySize(db_path_); + UMA_HISTOGRAM_MEMORY_KB("ResourceCoordinator.LocalDB.OnDiskSize", + db_ondisk_size_in_bytes / 1024); + } + + leveldb_env::Options options; + options.create_if_missing = true; + leveldb::Status status = + leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_); + + ReportInitStatus(kInitStatusHistogramLabel, status); + + if (status.ok()) + return opening_type; + + if (!ShouldAttemptDbRepair(status)) + return opening_type; + + if (RepairDatabase(db_path_.AsUTF8Unsafe())) { + status = leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_); + ReportInitStatus(kInitStatusAfterRepairHistogramLabel, status); + if (status.ok()) + return opening_type; + } + + // Delete the database and try to open it one last time. + if (leveldb_chrome::DeleteDB(db_path_, options).ok()) { + status = leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_); + ReportInitStatus(kInitStatusAfterDeleteHistogramLabel, status); + if (!status.ok()) + db_.reset(); + } + + return opening_type; +} + LevelDBSiteCharacteristicsDatabase::LevelDBSiteCharacteristicsDatabase( const base::FilePath& db_path) : blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits( @@ -322,4 +404,8 @@ return async_helper_->DBIsInitialized(); } +leveldb::DB* LevelDBSiteCharacteristicsDatabase::GetDBForTesting() { + return async_helper_->GetDBForTesting(); +} + } // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h index 65351cc8..e51244b 100644 --- a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h +++ b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h
@@ -45,6 +45,16 @@ bool DatabaseIsInitializedForTesting(); + // Returns a raw pointer to the database for testing purposes. Note that as + // the DB operations are made on a separate sequence it's recommended to call + // ScopedTaskEnvironment::RunUntilIdle before calling this function to ensure + // that the database has been fully initialized. The LevelDB implementation is + // thread safe. + leveldb::DB* GetDBForTesting(); + + static const size_t kDbVersion; + static const char kDbMetadataKey[]; + private: class AsyncHelper;
diff --git a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc index d3b5fae..d968b646 100644 --- a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc +++ b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc
@@ -4,9 +4,12 @@ #include "chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h" +#include <limits> + #include "base/bind.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_task_environment.h" @@ -83,15 +86,19 @@ EXPECT_TRUE(temp_dir_.Delete()); } - void OpenDB() { OpenDB(temp_dir_.GetPath()); } + void OpenDB() { + OpenDB(temp_dir_.GetPath().Append(FILE_PATH_LITERAL("LocalDB"))); + } void OpenDB(base::FilePath path) { db_ = std::make_unique<LevelDBSiteCharacteristicsDatabase>(path); WaitForAsyncOperationsToComplete(); EXPECT_TRUE(db_); + db_path_ = path; } const base::FilePath& GetTempPath() { return temp_dir_.GetPath(); } + const base::FilePath& GetDBPath() { return db_path_; } protected: // Try to read an entry from the database, returns true if the entry is @@ -136,6 +143,7 @@ const url::Origin kDummyOrigin = url::Origin::Create(GURL("http://foo.com")); + base::FilePath db_path_; base::test::ScopedTaskEnvironment task_env_; base::ScopedTempDir temp_dir_; std::unique_ptr<LevelDBSiteCharacteristicsDatabase> db_; @@ -192,7 +200,7 @@ db_.reset(); - EXPECT_TRUE(leveldb_chrome::CorruptClosedDBForTesting(temp_dir_.GetPath())); + EXPECT_TRUE(leveldb_chrome::CorruptClosedDBForTesting(GetDBPath())); base::HistogramTester histogram_tester; histogram_tester.ExpectTotalCount("ResourceCoordinator.LocalDB.DatabaseInit", @@ -234,4 +242,41 @@ WaitForAsyncOperationsToComplete(); } +TEST_F(LevelDBSiteCharacteristicsDatabaseTest, DBGetsClearedOnVersionUpgrade) { + leveldb::DB* raw_db = db_->GetDBForTesting(); + EXPECT_TRUE(raw_db); + + // Remove the entry containing the DB version number, this will cause the DB + // to be cleared the next time it gets opened. + leveldb::Status s = + raw_db->Delete(leveldb::WriteOptions(), + LevelDBSiteCharacteristicsDatabase::kDbMetadataKey); + EXPECT_TRUE(s.ok()); + + // Add some dummy data to the database to ensure the database gets cleared + // when upgrading it to the new version. + ::google::protobuf::int64 test_value = 42; + SiteCharacteristicsProto stored_proto; + InitSiteCharacteristicProto(&stored_proto, test_value); + db_->WriteSiteCharacteristicsIntoDB(kDummyOrigin, stored_proto); + WaitForAsyncOperationsToComplete(); + + db_.reset(); + + // Reopen the database and ensure that it has been cleared. + OpenDB(); + raw_db = db_->GetDBForTesting(); + std::string db_metadata; + s = raw_db->Get(leveldb::ReadOptions(), + LevelDBSiteCharacteristicsDatabase::kDbMetadataKey, + &db_metadata); + EXPECT_TRUE(s.ok()); + size_t version = std::numeric_limits<size_t>::max(); + EXPECT_TRUE(base::StringToSizeT(db_metadata, &version)); + EXPECT_EQ(LevelDBSiteCharacteristicsDatabase::kDbVersion, version); + + SiteCharacteristicsProto proto_temp; + EXPECT_FALSE(ReadFromDB(kDummyOrigin, &proto_temp)); +} + } // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker.cc b/chrome/browser/resource_coordinator/tab_load_tracker.cc index 6a1bba4..3aac683 100644 --- a/chrome/browser/resource_coordinator/tab_load_tracker.cc +++ b/chrome/browser/resource_coordinator/tab_load_tracker.cc
@@ -4,8 +4,11 @@ #include "chrome/browser/resource_coordinator/tab_load_tracker.h" +#include <utility> + +#include "base/logging.h" #include "base/stl_util.h" -#include "chrome/browser/ui/browser_tab_strip_tracker.h" +#include "chrome/browser/prerender/prerender_contents.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/web_contents.h" @@ -66,6 +69,33 @@ return state_counts_[static_cast<size_t>(LOADED)]; } +size_t TabLoadTracker::GetUiTabCount() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return ui_tab_state_counts_[static_cast<size_t>(UNLOADED)] + + ui_tab_state_counts_[static_cast<size_t>(LOADING)] + + ui_tab_state_counts_[static_cast<size_t>(LOADED)]; +} + +size_t TabLoadTracker::GetUiTabCount(LoadingState loading_state) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return ui_tab_state_counts_[static_cast<size_t>(loading_state)]; +} + +size_t TabLoadTracker::GetUnloadedUiTabCount() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return ui_tab_state_counts_[static_cast<size_t>(UNLOADED)]; +} + +size_t TabLoadTracker::GetLoadingUiTabCount() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return ui_tab_state_counts_[static_cast<size_t>(LOADING)]; +} + +size_t TabLoadTracker::GetLoadedUiTabCount() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return ui_tab_state_counts_[static_cast<size_t>(LOADED)]; +} + void TabLoadTracker::AddObserver(Observer* observer) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); observers_.AddObserver(observer); @@ -98,8 +128,11 @@ data.loading_state = loading_state; if (data.loading_state == LOADING) data.did_start_loading_seen = true; + data.is_ui_tab = IsUiTab(web_contents); tabs_.insert(std::make_pair(web_contents, data)); ++state_counts_[static_cast<size_t>(data.loading_state)]; + if (data.is_ui_tab) + ++ui_tab_state_counts_[static_cast<size_t>(data.loading_state)]; for (Observer& observer : observers_) observer.OnStartTracking(web_contents, loading_state); @@ -113,6 +146,12 @@ auto loading_state = it->second.loading_state; DCHECK_NE(0u, state_counts_[static_cast<size_t>(it->second.loading_state)]); --state_counts_[static_cast<size_t>(it->second.loading_state)]; + if (it->second.is_ui_tab) { + DCHECK_NE( + 0u, + ui_tab_state_counts_[static_cast<size_t>(it->second.loading_state)]); + --ui_tab_state_counts_[static_cast<size_t>(it->second.loading_state)]; + } tabs_.erase(it); for (Observer& observer : observers_) @@ -260,6 +299,11 @@ --state_counts_[static_cast<size_t>(previous_state)]; it->second.loading_state = loading_state; ++state_counts_[static_cast<size_t>(loading_state)]; + if (it->second.is_ui_tab) { + ++ui_tab_state_counts_[static_cast<size_t>(loading_state)]; + DCHECK_NE(0u, ui_tab_state_counts_[static_cast<size_t>(previous_state)]); + --ui_tab_state_counts_[static_cast<size_t>(previous_state)]; + } // If the destination state is LOADED, then also clear the // |did_start_loading_seen| state. @@ -274,6 +318,53 @@ observer.OnLoadingStateChange(web_contents, previous_state, loading_state); } +bool TabLoadTracker::IsUiTab(content::WebContents* web_contents) { + // TODO(crbug.com/836409): This should be able to check directly with the + // tabstrip UI or use a platform-independent tabstrip observer interface to + // learn about |web_contents| associated with the tabstrip, rather than + // checking for specific cases where |web_contents| is not a ui tab. + if (prerender::PrerenderContents::FromWebContents(web_contents) != nullptr) + return false; + return true; +} + +void TabLoadTracker::SwapTabContents(content::WebContents* old_contents, + content::WebContents* new_contents) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // TODO(crbug.com/836409): This should work by directly tracking tabs that are + // attached to UI surfaces instead of relying on being notified directly about + // tab contents swaps. + + // Transition |old_contents| to a non-UI tab. If a tab is being swapped out, + // then it should exist, we should be tracking it, and it should be a UI tab. + DCHECK(old_contents); + auto it = tabs_.find(old_contents); + DCHECK(it != tabs_.end()); + DCHECK(it->second.is_ui_tab); + it->second.is_ui_tab = false; + DCHECK_NE( + 0u, ui_tab_state_counts_[static_cast<size_t>(it->second.loading_state)]); + --ui_tab_state_counts_[static_cast<size_t>(it->second.loading_state)]; + + // Transition |new_contents| to a UI tab. + DCHECK(IsUiTab(new_contents)); + it = tabs_.find(new_contents); + // |new_contents| will not be tracked if a tab helper wasn't attached yet, + // which currently happens for dom distiller. In this case, the tab helper + // will be attached and we will start tracking it when it's swapped into the + // tab UI, which will happen later in this code path. + if (it == tabs_.end()) + return; + + // |new_contents| shouldn't be considered a UI tab yet. This should catch any + // new cases of non-tab web contents that attach tab helpers that we aren't + // handling. + DCHECK(!it->second.is_ui_tab); + // Promote |new_contents| to a UI tab. + it->second.is_ui_tab = true; + ++ui_tab_state_counts_[static_cast<size_t>(it->second.loading_state)]; +} + TabLoadTracker::Observer::Observer() {} TabLoadTracker::Observer::~Observer() {}
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker.h b/chrome/browser/resource_coordinator/tab_load_tracker.h index a2818f8..89239c7 100644 --- a/chrome/browser/resource_coordinator/tab_load_tracker.h +++ b/chrome/browser/resource_coordinator/tab_load_tracker.h
@@ -90,6 +90,18 @@ size_t GetLoadingTabCount() const; size_t GetLoadedTabCount() const; + // Returns the total number of UI tabs that are being tracked by this class. + // Some WebContents being tracked by this class may not yet be associated with + // a UI tab, e.g. prerender contents. To exclude these tabs from counts, use + // the Get*UiTabCount() methods. + size_t GetUiTabCount() const; + + // Returns the number of UI tabs in each state. + size_t GetUiTabCount(LoadingState loading_state) const; + size_t GetUnloadedUiTabCount() const; + size_t GetLoadingUiTabCount() const; + size_t GetLoadedUiTabCount() const; + // Adds/removes an observer. It is up to the observer to ensure their lifetime // exceeds that of the TabLoadTracker, as is removed prior to its destruction. void AddObserver(Observer* observer); @@ -99,6 +111,11 @@ void TransitionStateForTesting(content::WebContents* web_contents, LoadingState loading_state); + // Called from CoreTabHelperDelegates when |new_contents| is replacing + // |old_contents| in a tab. + void SwapTabContents(content::WebContents* old_contents, + content::WebContents* new_contents); + protected: // This allows the singleton constructor access to the protected constructor. friend class base::NoDestructor<TabLoadTracker>; @@ -141,6 +158,14 @@ // from the TabManager. void OnPageAlmostIdle(content::WebContents* web_contents); + // Returns true if |web_contents| is a UI tab and false otherwise. This is + // used to filter out cases where tab helpers are attached to a non-UI tab + // WebContents, e.g prerender contents. + // + // This is virtual and protected for unittesting to control when web + // contentses are considered ui tabs. + virtual bool IsUiTab(content::WebContents* web_contents); + private: // For unittesting. friend class TestTabLoadTracker; @@ -149,6 +174,7 @@ struct WebContentsData { LoadingState loading_state = LoadingState::UNLOADED; bool did_start_loading_seen = false; + bool is_ui_tab = false; }; using TabMap = base::flat_map<content::WebContents*, WebContentsData>; @@ -168,12 +194,17 @@ LoadingState loading_state, bool validate_transition); - // The list of known WebContents and their states. + // The list of known WebContents and their states. This includes both UI and + // non-UI tabs. TabMap tabs_; // The counts of tabs in each state. size_t state_counts_[static_cast<size_t>(LoadingState::kMaxValue) + 1] = {0}; + // The counts of UI tabs in each state. + size_t ui_tab_state_counts_[static_cast<size_t>(LoadingState::kMaxValue) + + 1] = {0}; + base::ObserverList<Observer> observers_; SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc b/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc index 9dfdfa3b..2b0a2c9 100644 --- a/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc +++ b/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc
@@ -4,10 +4,18 @@ #include "chrome/browser/resource_coordinator/tab_load_tracker.h" +#include <memory> +#include <vector> + #include "base/process/kill.h" #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" +#include "chrome/browser/prerender/prerender_handle.h" +#include "chrome/browser/prerender/prerender_manager.h" +#include "chrome/browser/prerender/prerender_manager_factory.h" +#include "chrome/browser/prerender/prerender_test_utils.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/testing_profile.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/test/mock_render_process_host.h" #include "content/public/test/web_contents_tester.h" @@ -35,7 +43,7 @@ using TabLoadTracker::OnPageAlmostIdle; using TabLoadTracker::DetermineLoadingState; - TestTabLoadTracker() {} + TestTabLoadTracker() : all_tabs_are_non_ui_tabs_(false) {} virtual ~TestTabLoadTracker() {} // Some accessors for TabLoadTracker internals. @@ -49,6 +57,19 @@ return false; return it->second.did_start_loading_seen; } + + bool IsUiTab(content::WebContents* web_contents) override { + if (all_tabs_are_non_ui_tabs_) + return false; + return TabLoadTracker::IsUiTab(web_contents); + } + + void SetAllTabsAreNonUiTabs(bool enabled) { + all_tabs_are_non_ui_tabs_ = enabled; + } + + private: + bool all_tabs_are_non_ui_tabs_; }; // A mock observer class. @@ -143,7 +164,18 @@ EXPECT_EQ(loaded, tracker().GetLoadedTabCount()); } - void StateTransitionsTest(bool enable_pai); + void ExpectUiTabCounts(size_t tabs, + size_t unloaded, + size_t loading, + size_t loaded) { + EXPECT_EQ(tabs, unloaded + loading + loaded); + EXPECT_EQ(tabs, tracker().GetUiTabCount()); + EXPECT_EQ(unloaded, tracker().GetUnloadedUiTabCount()); + EXPECT_EQ(loading, tracker().GetLoadingUiTabCount()); + EXPECT_EQ(loaded, tracker().GetLoadedUiTabCount()); + } + + void StateTransitionsTest(bool enable_pai, bool use_non_ui_tabs); TestTabLoadTracker& tracker() { return tracker_; } MockObserver& observer() { return observer_; } @@ -169,6 +201,17 @@ SCOPED_TRACE(""); \ ExpectTabCounts(a, b, c, d); \ } +#define EXPECT_UI_TAB_COUNTS(a, b, c, d) \ + { \ + SCOPED_TRACE(""); \ + ExpectUiTabCounts(a, b, c, d); \ + } +#define EXPECT_TAB_AND_UI_TAB_COUNTS(a, b, c, d) \ + { \ + SCOPED_TRACE(""); \ + ExpectTabCounts(a, b, c, d); \ + ExpectUiTabCounts(a, b, c, d); \ + } TEST_F(TabLoadTrackerTest, DetermineLoadingState) { auto* tester1 = content::WebContentsTester::For(contents1()); @@ -186,8 +229,10 @@ EXPECT_EQ(LoadingState::LOADED, tracker().DetermineLoadingState(contents1())); } -void TabLoadTrackerTest::StateTransitionsTest(bool enable_pai) { +void TabLoadTrackerTest::StateTransitionsTest(bool enable_pai, + bool use_non_ui_tabs) { SetPageAlmostIdleFeatureEnabled(enable_pai); + tracker().SetAllTabsAreNonUiTabs(use_non_ui_tabs); auto* tester1 = content::WebContentsTester::For(contents1()); auto* tester2 = content::WebContentsTester::For(contents2()); @@ -199,20 +244,35 @@ tester3->NavigateAndCommit(GURL("http://bar.com")); tester3->TestSetIsLoading(false); - // Add the contents to the trackers. + // Add the contents to the tracker. EXPECT_CALL(observer(), OnStartTracking(contents1(), LoadingState::UNLOADED)); tracker().StartTracking(contents1()); - EXPECT_TAB_COUNTS(1, 1, 0, 0); + if (use_non_ui_tabs) { + EXPECT_TAB_COUNTS(1, 1, 0, 0); + EXPECT_UI_TAB_COUNTS(0, 0, 0, 0); + } else { + EXPECT_TAB_AND_UI_TAB_COUNTS(1, 1, 0, 0); + } testing::Mock::VerifyAndClearExpectations(&observer()); EXPECT_CALL(observer(), OnStartTracking(contents2(), LoadingState::LOADING)); tracker().StartTracking(contents2()); - EXPECT_TAB_COUNTS(2, 1, 1, 0); + if (use_non_ui_tabs) { + EXPECT_TAB_COUNTS(2, 1, 1, 0); + EXPECT_UI_TAB_COUNTS(0, 0, 0, 0); + } else { + EXPECT_TAB_AND_UI_TAB_COUNTS(2, 1, 1, 0); + } testing::Mock::VerifyAndClearExpectations(&observer()); EXPECT_CALL(observer(), OnStartTracking(contents3(), LoadingState::LOADED)); tracker().StartTracking(contents3()); - EXPECT_TAB_COUNTS(3, 1, 1, 1); + if (use_non_ui_tabs) { + EXPECT_TAB_COUNTS(3, 1, 1, 1); + EXPECT_UI_TAB_COUNTS(0, 0, 0, 0); + } else { + EXPECT_TAB_AND_UI_TAB_COUNTS(3, 1, 1, 1); + } testing::Mock::VerifyAndClearExpectations(&observer()); // Start observers for the contents. @@ -230,10 +290,20 @@ if (enable_pai) { // The state transition should only occur *after* the PAI signal when that // feature is enabled. - EXPECT_TAB_COUNTS(3, 1, 1, 1); + if (use_non_ui_tabs) { + EXPECT_TAB_COUNTS(3, 1, 1, 1); + EXPECT_UI_TAB_COUNTS(0, 0, 0, 0); + } else { + EXPECT_TAB_AND_UI_TAB_COUNTS(3, 1, 1, 1); + } tracker().OnPageAlmostIdle(contents2()); } - EXPECT_TAB_COUNTS(3, 1, 0, 2); + if (use_non_ui_tabs) { + EXPECT_TAB_COUNTS(3, 1, 0, 2); + EXPECT_UI_TAB_COUNTS(0, 0, 0, 0); + } else { + EXPECT_TAB_AND_UI_TAB_COUNTS(3, 1, 0, 2); + } testing::Mock::VerifyAndClearExpectations(&observer()); // Start the loading for contents1. @@ -241,7 +311,12 @@ OnLoadingStateChange(contents1(), LoadingState::UNLOADED, LoadingState::LOADING)); tester1->NavigateAndCommit(GURL("http://baz.com")); - EXPECT_TAB_COUNTS(3, 0, 1, 2); + if (use_non_ui_tabs) { + EXPECT_TAB_COUNTS(3, 0, 1, 2); + EXPECT_UI_TAB_COUNTS(0, 0, 0, 0); + } else { + EXPECT_TAB_AND_UI_TAB_COUNTS(3, 0, 1, 2); + } testing::Mock::VerifyAndClearExpectations(&observer()); // Stop the loading with an error. The tab should go back to a LOADED @@ -251,7 +326,12 @@ LoadingState::LOADED)); tester1->TestDidFailLoadWithError(GURL("http://baz.com"), 500, base::UTF8ToUTF16("server error")); - ExpectTabCounts(3, 0, 0, 3); + if (use_non_ui_tabs) { + EXPECT_TAB_COUNTS(3, 0, 0, 3); + EXPECT_UI_TAB_COUNTS(0, 0, 0, 0); + } else { + EXPECT_TAB_AND_UI_TAB_COUNTS(3, 0, 0, 3); + } testing::Mock::VerifyAndClearExpectations(&observer()); // Crash the render process corresponding to the main frame of a tab. This @@ -263,16 +343,163 @@ static_cast<content::MockRenderProcessHost*>( contents1()->GetMainFrame()->GetProcess()); rph->SimulateCrash(); - ExpectTabCounts(3, 1, 0, 2); + if (use_non_ui_tabs) { + EXPECT_TAB_COUNTS(3, 1, 0, 2); + EXPECT_UI_TAB_COUNTS(0, 0, 0, 0); + } else { + EXPECT_TAB_AND_UI_TAB_COUNTS(3, 1, 0, 2); + } testing::Mock::VerifyAndClearExpectations(&observer()); } TEST_F(TabLoadTrackerTest, StateTransitions) { - StateTransitionsTest(false); + StateTransitionsTest(false /* enable_pai */, false /* use_non_ui_tabs */); } TEST_F(TabLoadTrackerTest, StateTransitionsPAI) { - StateTransitionsTest(true); + StateTransitionsTest(true /* enable_pai */, false /* use_non_ui_tabs */); +} + +TEST_F(TabLoadTrackerTest, StateTransitionsNonUiTabs) { + StateTransitionsTest(false /* enable_pai */, true /* use_non_ui_tabs */); +} + +TEST_F(TabLoadTrackerTest, StateTransitionsPAINonUiTabs) { + StateTransitionsTest(true /* enable_pai */, true /* use_non_ui_tabs */); +} + +TEST_F(TabLoadTrackerTest, PrerenderContentsDoesNotChangeUiTabCounts) { + auto* tester1 = content::WebContentsTester::For(contents1()); + tester1->NavigateAndCommit(GURL("http://baz.com")); + + // Add the contents to the tracker. + EXPECT_CALL(observer(), OnStartTracking(contents1(), LoadingState::LOADING)); + tracker().StartTracking(contents1()); + EXPECT_TAB_AND_UI_TAB_COUNTS(1, 0, 1, 0); + testing::Mock::VerifyAndClearExpectations(&observer()); + + EXPECT_CALL(observer(), OnStartTracking(contents2(), LoadingState::UNLOADED)); + tracker().StartTracking(contents2()); + EXPECT_TAB_AND_UI_TAB_COUNTS(2, 1, 1, 0); + testing::Mock::VerifyAndClearExpectations(&observer()); + + // Start observers for the contents. + TestWebContentsObserver observer1(contents1(), &tracker()); + TestWebContentsObserver observer2(contents2(), &tracker()); + + // Prerender some contents. + prerender::test_utils::RestorePrerenderMode restore_prerender_mode; + prerender::PrerenderManager::SetMode( + prerender::PrerenderManager::PRERENDER_MODE_ENABLED); + prerender::PrerenderManager* prerender_manager = + prerender::PrerenderManagerFactory::GetForBrowserContext(profile()); + GURL url("http://www.example.com"); + const gfx::Size kSize(640, 480); + std::unique_ptr<prerender::PrerenderHandle> prerender_handle( + prerender_manager->AddPrerenderFromOmnibox( + url, contents1()->GetController().GetDefaultSessionStorageNamespace(), + kSize)); + const std::vector<content::WebContents*> contentses = + prerender_manager->GetAllPrerenderingContents(); + ASSERT_EQ(1U, contentses.size()); + + // Prerendering should not change the UI tab counts, but should increase + // overall tab count. Note, contentses[0] is UNLOADED since it is not a test + // web contents and therefore hasn't started receiving data. + TestWebContentsObserver prerender_observer(contentses[0], &tracker()); + EXPECT_CALL(observer(), + OnStartTracking(contentses[0], LoadingState::UNLOADED)); + tracker().StartTracking(contentses[0]); + EXPECT_TAB_COUNTS(3, 2, 1, 0); + EXPECT_UI_TAB_COUNTS(2, 1, 1, 0); + testing::Mock::VerifyAndClearExpectations(&observer()); + + prerender_manager->CancelAllPrerenders(); +} + +TEST_F(TabLoadTrackerTest, SwapInUiTabContents) { + auto* tester1 = content::WebContentsTester::For(contents1()); + tester1->NavigateAndCommit(GURL("http://baz.com")); + + // Add the contents to the tracker. + EXPECT_CALL(observer(), OnStartTracking(contents1(), LoadingState::LOADING)); + tracker().StartTracking(contents1()); + EXPECT_TAB_AND_UI_TAB_COUNTS(1, 0, 1, 0); + testing::Mock::VerifyAndClearExpectations(&observer()); + + EXPECT_CALL(observer(), OnStartTracking(contents2(), LoadingState::UNLOADED)); + tracker().StartTracking(contents2()); + EXPECT_TAB_AND_UI_TAB_COUNTS(2, 1, 1, 0); + testing::Mock::VerifyAndClearExpectations(&observer()); + + // Start observers for the contents. + TestWebContentsObserver observer1(contents1(), &tracker()); + TestWebContentsObserver observer2(contents2(), &tracker()); + + // Simulate non-ui tab contents running in the background and getting swapped + // in. Non-ui tabs should not change the ui tab counts, but should change the + // overall tab counts. + std::unique_ptr<content::WebContents> non_ui_tab_contents = + CreateTestWebContents(); + EXPECT_CALL(observer(), OnStartTracking(non_ui_tab_contents.get(), + LoadingState::UNLOADED)); + tracker().SetAllTabsAreNonUiTabs(true); + tracker().StartTracking(non_ui_tab_contents.get()); + EXPECT_TAB_COUNTS(3, 2, 1, 0); + EXPECT_UI_TAB_COUNTS(2, 1, 1, 0); + testing::Mock::VerifyAndClearExpectations(&observer()); + // Swap in the prerender contents and simulate resulting tab strip swap. + // |non_ui_tab_contents| is already being tracked. The UI tab count should + // remain stable through the swap. + EXPECT_CALL(observer(), OnStopTracking(contents1(), LoadingState::LOADING)); + tracker().SetAllTabsAreNonUiTabs(false); + tracker().SwapTabContents(contents1(), non_ui_tab_contents.get()); + // After swap, but before we stop tracking the swapped-out contents. The UI + // tab counts should be in the end-state, but the total tab counts will be in + // the pre-swap state while the swapped-out contents is still being tracked. + EXPECT_TAB_COUNTS(3, 2, 1, 0); + EXPECT_UI_TAB_COUNTS(2, 2, 0, 0); + tracker().StopTracking(contents1()); + EXPECT_TAB_AND_UI_TAB_COUNTS(2, 2, 0, 0); + testing::Mock::VerifyAndClearExpectations(&observer()); +} + +TEST_F(TabLoadTrackerTest, SwapInUntrackedContents) { + auto* tester1 = content::WebContentsTester::For(contents1()); + tester1->NavigateAndCommit(GURL("http://baz.com")); + + // Add the contents to the tracker. + EXPECT_CALL(observer(), OnStartTracking(contents1(), LoadingState::LOADING)); + tracker().StartTracking(contents1()); + EXPECT_TAB_AND_UI_TAB_COUNTS(1, 0, 1, 0); + testing::Mock::VerifyAndClearExpectations(&observer()); + + EXPECT_CALL(observer(), OnStartTracking(contents2(), LoadingState::UNLOADED)); + tracker().StartTracking(contents2()); + EXPECT_TAB_AND_UI_TAB_COUNTS(2, 1, 1, 0); + testing::Mock::VerifyAndClearExpectations(&observer()); + + // Create an untracked web contents in the UNLOADED state, and swap it with + // the contents in the LOADING state. Since |untracked_contents| has no tab + // helper attached, swapping it in shouldn't changed the tab count. + std::unique_ptr<content::WebContents> untracked_contents = + CreateTestWebContents(); + tracker().SwapTabContents(contents1(), untracked_contents.get()); + // The total counts will remain stable since swapping out doesn't cause any + // web contents to stop being tracking. However, the swapped-out contents are + // no longer included in UI tab counts, and the swapped-in contents won't be + // until it is tracked. + EXPECT_TAB_COUNTS(2, 1, 1, 0); + EXPECT_UI_TAB_COUNTS(1, 1, 0, 0); + + // Simulate swap in tab strip, which would cause |untracked_contents| to be + // tracked and the tab counts to change. + EXPECT_CALL(observer(), OnStopTracking(contents1(), LoadingState::LOADING)); + EXPECT_CALL(observer(), OnStartTracking(untracked_contents.get(), + LoadingState::UNLOADED)); + tracker().StopTracking(contents1()); + tracker().StartTracking(untracked_contents.get()); + EXPECT_TAB_AND_UI_TAB_COUNTS(2, 2, 0, 0); } } // namespace resource_coordinator
diff --git a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc index a94040f47..ad1a19a7 100644 --- a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc +++ b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc
@@ -61,22 +61,28 @@ using ResourceRequestIncidentMessage = ClientIncidentReport::IncidentData::ResourceRequestIncident; - typedef base::Callback<void(std::unique_ptr<ResourceRequestIncidentMessage>)> - OnResultCallback; + using OnResultCallback = + base::OnceCallback<void(std::unique_ptr<ResourceRequestIncidentMessage>)>; - ResourceRequestDetectorClient( + static void Start( const GURL& resource_url, const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager, - const OnResultCallback& callback) - : database_manager_(database_manager) - , callback_(callback) { + OnResultCallback callback) { + auto client = base::WrapRefCounted(new ResourceRequestDetectorClient( + std::move(database_manager), std::move(callback))); content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&ResourceRequestDetectorClient::StartCheck, this, + base::BindOnce(&ResourceRequestDetectorClient::StartCheck, client, resource_url)); } private: + ResourceRequestDetectorClient( + scoped_refptr<SafeBrowsingDatabaseManager> database_manager, + OnResultCallback callback) + : database_manager_(std::move(database_manager)), + callback_(std::move(callback)) {} + friend class base::RefCountedThreadSafe<ResourceRequestDetectorClient>; ~ResourceRequestDetectorClient() override {} @@ -106,7 +112,7 @@ incident_data->set_digest(threat_hash); content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, - base::BindOnce(callback_, std::move(incident_data))); + base::BindOnce(std::move(callback_), std::move(incident_data))); } Release(); // Balanced in StartCheck. } @@ -152,11 +158,11 @@ if (request->resource_type == content::RESOURCE_TYPE_SUB_FRAME || request->resource_type == content::RESOURCE_TYPE_SCRIPT || request->resource_type == content::RESOURCE_TYPE_OBJECT) { - new ResourceRequestDetectorClient( + ResourceRequestDetectorClient::Start( request->url, database_manager_, - base::Bind(&ResourceRequestDetector::ReportIncidentOnUIThread, - weak_ptr_factory_.GetWeakPtr(), request->render_process_id, - request->render_frame_id)); + base::BindOnce(&ResourceRequestDetector::ReportIncidentOnUIThread, + weak_ptr_factory_.GetWeakPtr(), + request->render_process_id, request->render_frame_id)); } }
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc index e185f97..7fc6ac4 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -247,7 +247,7 @@ TestThreatDetailsFactory() : details_() {} ~TestThreatDetailsFactory() override {} - ThreatDetails* CreateThreatDetails( + scoped_refptr<ThreatDetails> CreateThreatDetails( BaseUIManager* delegate, WebContents* web_contents, const security_interstitials::UnsafeResource& unsafe_resource, @@ -256,11 +256,13 @@ ReferrerChainProvider* referrer_chain_provider, bool trim_to_ad_tags, ThreatDetailsDoneCallback done_callback) override { - details_ = new ThreatDetails(delegate, web_contents, unsafe_resource, - url_loader_factory, history_service, - referrer_chain_provider, trim_to_ad_tags, - done_callback); - return details_; + auto details = base::WrapRefCounted(new ThreatDetails( + delegate, web_contents, unsafe_resource, url_loader_factory, + history_service, referrer_chain_provider, trim_to_ad_tags, + done_callback)); + details_ = details.get(); + details->StartCollection(); + return details; } ThreatDetails* get_details() { return details_; }
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc index 992b172..0dfae99 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -1043,14 +1043,7 @@ EXPECT_TRUE(hit_report().is_subresource); } -// TODO(https://crbug.com/860445) - Reenable this once potential race condition -// is addressed, which is triggered in certain conditions under MSAN, see bug. -#if defined(MEMORY_SANITIZER) -#define MAYBE_MalwareImg DISABLED_MalwareImg -#else -#define MAYBE_MalwareImg MalwareImg -#endif -IN_PROC_BROWSER_TEST_P(SafeBrowsingServiceMetadataTest, MAYBE_MalwareImg) { +IN_PROC_BROWSER_TEST_P(SafeBrowsingServiceMetadataTest, MalwareImg) { GURL main_url = embedded_test_server()->GetURL(kMalwarePage); GURL img_url = embedded_test_server()->GetURL(kMalwareImg);
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc index 9f6fa03..082a1f2 100644 --- a/chrome/browser/safe_browsing/threat_details_unittest.cc +++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -142,6 +142,8 @@ size_t done_callback_count() { return done_callback_count_; } + void StartCollection() { ThreatDetails::StartCollection(); } + private: ~ThreatDetailsWrap() override {} @@ -174,7 +176,7 @@ class MockReferrerChainProvider : public ReferrerChainProvider { public: - virtual ~MockReferrerChainProvider(){}; + virtual ~MockReferrerChainProvider() {} MOCK_METHOD3(IdentifyReferrerChainByWebContents, AttributionResult(content::WebContents* web_contents, int user_gesture_count_limit, @@ -402,6 +404,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); std::string serialized = WaitForThreatDetailsDone( report.get(), true /* did_proceed*/, 1 /* num_visit */); @@ -457,6 +460,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); std::string serialized = WaitForThreatDetailsDone( report.get(), true /* did_proceed*/, 1 /* num_visit */); @@ -507,6 +511,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); std::string serialized = WaitForThreatDetailsDone( report.get(), false /* did_proceed*/, 1 /* num_visit */); @@ -555,6 +560,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); // Send a message from the DOM, with 2 nodes, a parent and a child. std::vector<mojom::ThreatDOMDetailsNodePtr> params; @@ -777,6 +783,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap( ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); std::vector<mojom::ThreatDOMDetailsNodePtr> outer_params_copy; for (auto& node : outer_params) { @@ -833,6 +840,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap( ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); // Send both sets of nodes from different render frames. report->OnReceivedThreatDOMDetails(nullptr, child_rfh, @@ -959,6 +967,8 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); + base::HistogramTester histograms; // Send both sets of nodes from different render frames. @@ -1214,6 +1224,7 @@ new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get(), /*trim_to_ad_tags=*/true); + trimmed_report->StartCollection(); // Send both sets of nodes from different render frames. trimmed_report->OnReceivedThreatDOMDetails(nullptr, child_rfh, @@ -1287,6 +1298,7 @@ new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get(), /*trim_to_ad_tags=*/true); + trimmed_report->StartCollection(); // Send both sets of nodes from different render frames. trimmed_report->OnReceivedThreatDOMDetails(nullptr, child_rfh, @@ -1318,6 +1330,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); std::string serialized = WaitForThreatDetailsDone( report.get(), true /* did_proceed*/, 0 /* num_visit */); @@ -1390,6 +1403,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); // Simulate clicking don't proceed. controller().DiscardNonCommittedEntries(); @@ -1450,6 +1464,8 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); + std::string serialized = WaitForThreatDetailsDone( report.get(), true /* did_proceed*/, 1 /* num_visit */); @@ -1498,6 +1514,8 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); + std::string serialized = WaitForThreatDetailsDone( report.get(), true /* did_proceed*/, 1 /* num_visit */); @@ -1531,6 +1549,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap( ui_manager_.get(), web_contents(), resource, test_shared_loader_factory_, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); SimulateFillCache(kThreatURL); @@ -1609,6 +1628,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap( ui_manager_.get(), web_contents(), resource, test_shared_loader_factory_, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); SimulateFillCache(kThreatURLHttps); @@ -1684,6 +1704,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap( ui_manager_.get(), web_contents(), resource, test_shared_loader_factory_, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); // Simulate no cache entry found. test_url_loader_factory_.AddResponse( @@ -1749,6 +1770,7 @@ scoped_refptr<ThreatDetailsWrap> report = new ThreatDetailsWrap(ui_manager_.get(), web_contents(), resource, NULL, history_service(), referrer_chain_provider_.get()); + report->StartCollection(); // The redirects collection starts after the IPC from the DOM is fired. std::vector<mojom::ThreatDOMDetailsNodePtr> params;
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc index 47de1aa..028555e 100644 --- a/chrome/browser/signin/dice_browsertest.cc +++ b/chrome/browser/signin/dice_browsertest.cc
@@ -694,9 +694,9 @@ SendRefreshTokenResponse(); EXPECT_EQ(GetMainAccountID(), GetSigninManager()->GetAuthenticatedAccountId()); - // Old token must be revoked silently. + + // Old token must not be revoked (see http://crbug.com/865189). EXPECT_EQ(0, token_revoked_notification_count_); - WaitForTokenRevokedCount(1); EXPECT_EQ(1, reconcilor_blocked_count_); WaitForReconcilorUnblockedCount(1); @@ -896,9 +896,10 @@ SendRefreshTokenResponse(); EXPECT_EQ(GetMainAccountID(), GetSigninManager()->GetAuthenticatedAccountId()); - // Old token must be revoked silently. + + // Old token must not be revoked (see http://crbug.com/865189). EXPECT_EQ(0, token_revoked_notification_count_); - WaitForTokenRevokedCount(1); + EXPECT_EQ(1, reconcilor_blocked_count_); WaitForReconcilorUnblockedCount(1); }
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc index 9751c77..adb742f 100644 --- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc +++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
@@ -761,8 +761,9 @@ DCHECK(!account_id.empty()); DCHECK(!refresh_token.empty()); + bool is_refresh_token_invalidated = refresh_token == kInvalidRefreshToken; GoogleServiceAuthError error = - (refresh_token == kInvalidRefreshToken) + is_refresh_token_invalidated ? GoogleServiceAuthError::FromInvalidGaiaCredentialsReason( GoogleServiceAuthError::InvalidGaiaCredentialsReason:: CREDENTIALS_REJECTED_BY_CLIENT) @@ -775,7 +776,21 @@ DCHECK_NE(refresh_token, refresh_tokens_[account_id]->refresh_token()); VLOG(1) << "MutablePO2TS::UpdateCredentials; Refresh Token was present. " << "account_id=" << account_id; - RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token()); + + // The old refresh token must be revoked on the server only when it is + // invalidated. + // + // The refresh token is updated to a new valid one in case of reauth. + // In the reauth case the old and the new refresh tokens have the same + // device ID. When revoking a refresh token on the server, Gaia revokes + // all the refresh tokens that have the same device ID. + // Therefore, the old refresh token must not be revoked on the server + // when it is updated to a new valid one (otherwise the new refresh token + // would also be invalidated server-side). + // See http://crbug.com/865189 for more information about this regression. + if (is_refresh_token_invalidated) + RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token()); + refresh_tokens_[account_id]->set_refresh_token(refresh_token); UpdateAuthError(account_id, error); } else {
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc index d5776b5..c87d0e33 100644 --- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc +++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -760,9 +760,10 @@ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty()); ExpectOneTokenAvailableNotification(); - // Update the token. + // Updating the token does not revoke the old one. + // Regression test for http://crbug.com/865189 oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token2"); - EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size()); + EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty()); ExpectOneTokenAvailableNotification(); // Flush the server revokes.
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index 60b26cfa..e53ea55 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -47,6 +47,7 @@ #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h" +#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h" #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h" @@ -609,6 +610,17 @@ ->change_processor() ->GetControllerDelegateOnUIThread(); } + case syncer::AUTOFILL_WALLET_METADATA: { + // TODO(feuunk): This doesn't allow switching which database to use at + // runtime. This should be fixed as part of the USS migration for + // payments. + auto service = account_web_data_service_ ? account_web_data_service_ + : profile_web_data_service_; + return autofill::AutofillWalletMetadataSyncBridge::FromWebDataService( + service.get()) + ->change_processor() + ->GetControllerDelegateOnUIThread(); + } #if defined(OS_CHROMEOS) case syncer::PRINTERS: return chromeos::SyncedPrintersManagerFactory::GetForBrowserContext(
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 111041b4..03555a2 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1889,8 +1889,6 @@ "ash/network/network_portal_notification_controller.h", "ash/network/network_state_notifier.cc", "ash/network/network_state_notifier.h", - "ash/network/networking_config_delegate_chromeos.cc", - "ash/network/networking_config_delegate_chromeos.h", "ash/network/tether_notification_presenter.cc", "ash/network/tether_notification_presenter.h", "ash/session_controller_client.cc", @@ -3486,9 +3484,7 @@ } if (!is_chromeos) { - sources += [ - "views/screen_capture_notification_ui_views.cc", - ] + sources += [ "views/screen_capture_notification_ui_views.cc" ] } if (is_mac) {
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc index 32a7b88..151c564 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate.cc +++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -22,7 +22,6 @@ #include "chrome/browser/ui/ash/chrome_keyboard_ui.h" #include "chrome/browser/ui/ash/chrome_screenshot_grabber.h" #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" -#include "chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h" #include "chrome/browser/ui/ash/session_controller_client.h" #include "chrome/browser/ui/ash/session_util.h" #include "chrome/browser/ui/browser.h" @@ -86,12 +85,9 @@ } // namespace -ChromeShellDelegate::ChromeShellDelegate() - : networking_config_delegate_( - std::make_unique<chromeos::NetworkingConfigDelegateChromeos>()) { -} +ChromeShellDelegate::ChromeShellDelegate() = default; -ChromeShellDelegate::~ChromeShellDelegate() {} +ChromeShellDelegate::~ChromeShellDelegate() = default; service_manager::Connector* ChromeShellDelegate::GetShellConnector() const { return content::ServiceManagerConnection::GetForProcess()->GetConnector(); @@ -140,11 +136,6 @@ return new AccessibilityDelegateImpl; } -ash::NetworkingConfigDelegate* -ChromeShellDelegate::GetNetworkingConfigDelegate() { - return networking_config_delegate_.get(); -} - std::unique_ptr<ash::ScreenshotDelegate> ChromeShellDelegate::CreateScreenshotDelegate() { return std::make_unique<ChromeScreenshotGrabber>();
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h index 923d610..51e7944 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate.h +++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -26,15 +26,12 @@ bool CanShowWindowForUser(aura::Window* window) const override; void PreInit() override; std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override; - ash::NetworkingConfigDelegate* GetNetworkingConfigDelegate() override; std::unique_ptr<ash::ScreenshotDelegate> CreateScreenshotDelegate() override; ash::AccessibilityDelegate* CreateAccessibilityDelegate() override; void OpenKeyboardShortcutHelpPage() const override; ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override; private: - std::unique_ptr<ash::NetworkingConfigDelegate> networking_config_delegate_; - DISALLOW_COPY_AND_ASSIGN(ChromeShellDelegate); };
diff --git a/chrome/browser/ui/ash/network/DEPS b/chrome/browser/ui/ash/network/DEPS index 96b7bd5..1601c9d 100644 --- a/chrome/browser/ui/ash/network/DEPS +++ b/chrome/browser/ui/ash/network/DEPS
@@ -1,10 +1,3 @@ include_rules = [ "+components/captive_portal", ] - -specific_include_rules = { - # TODO(mash): Fix. https://crbug.com/651157 - "networking_config_delegate_chromeos\.h": [ - "+ash/system/networking_config_delegate.h", - ], -}
diff --git a/chrome/browser/ui/ash/network/network_state_notifier.cc b/chrome/browser/ui/ash/network/network_state_notifier.cc index c23fb7d..f4f0fee 100644 --- a/chrome/browser/ui/ash/network/network_state_notifier.cc +++ b/chrome/browser/ui/ash/network/network_state_notifier.cc
@@ -227,7 +227,7 @@ void NetworkStateNotifier::UpdateVpnConnectionState(const NetworkState* vpn) { if (vpn->path() == connected_vpn_) { if (!vpn->IsConnectedState() && !vpn->IsConnectingState()) { - if (vpn->vpn_provider_type() != shill::kProviderArcVpn) { + if (vpn->GetVpnProviderType() != shill::kProviderArcVpn) { ShowVpnDisconnectedNotification(vpn); } connected_vpn_.clear();
diff --git a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos_browsertest.cc b/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc similarity index 82% rename from chrome/browser/ui/ash/network/networking_config_delegate_chromeos_browsertest.cc rename to chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc index 25d0007d..fdf888a 100644 --- a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos_browsertest.cc +++ b/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h" - #include "ash/public/cpp/ash_view_ids.h" #include "ash/public/interfaces/constants.mojom.h" #include "ash/public/interfaces/system_tray_test_api.mojom.h" @@ -20,16 +18,15 @@ namespace { -using NetworkingConfigDelegateChromeosTest = extensions::ExtensionBrowserTest; +using NetworkingConfigChromeosTest = extensions::ExtensionBrowserTest; // Tests that an extension registering itself as handling a Wi-Fi SSID updates // the ash system tray network item. -IN_PROC_BROWSER_TEST_F(NetworkingConfigDelegateChromeosTest, SystemTrayItem) { +IN_PROC_BROWSER_TEST_F(NetworkingConfigChromeosTest, SystemTrayItem) { // Load the extension and wait for the background page script to run. This // registers the extension as the network config handler for wifi1. ExtensionTestMessageListener listener("done", false); - ASSERT_TRUE( - LoadExtension(test_data_dir_.AppendASCII("networking_config_delegate"))); + ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("networking_config"))); ASSERT_TRUE(listener.WaitUntilSatisfied()); // Connect to ash. @@ -45,7 +42,7 @@ // Expect that the extension-controlled VPN item appears. base::string16 expected_tooltip = l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_EXTENSION_CONTROLLED_WIFI, - base::UTF8ToUTF16("NetworkingConfigDelegate test extension")); + base::UTF8ToUTF16("NetworkingConfig test extension")); base::string16 tooltip; wait_for.GetBubbleViewTooltip(ash::VIEW_ID_EXTENSION_CONTROLLED_WIFI, &tooltip);
diff --git a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.cc b/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.cc deleted file mode 100644 index e28a135..0000000 --- a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.cc +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h" - -#include <memory> -#include <string> - -#include "base/strings/string_number_conversions.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" -#include "extensions/browser/api/networking_config/networking_config_service.h" -#include "extensions/browser/api/networking_config/networking_config_service_factory.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/common/extension.h" - -namespace chromeos { - -NetworkingConfigDelegateChromeos::NetworkingConfigDelegateChromeos() {} - -NetworkingConfigDelegateChromeos::~NetworkingConfigDelegateChromeos() {} - -std::unique_ptr<const ash::NetworkingConfigDelegate::ExtensionInfo> -NetworkingConfigDelegateChromeos::LookUpExtensionForNetwork( - const std::string& guid) { - chromeos::NetworkStateHandler* handler = - chromeos::NetworkHandler::Get()->network_state_handler(); - const chromeos::NetworkState* network_state = - handler->GetNetworkStateFromGuid(guid); - if (!network_state) - return nullptr; - std::string hex_ssid = network_state->GetHexSsid(); - Profile* profile = ProfileManager::GetActiveUserProfile(); - extensions::NetworkingConfigService* networking_config_service = - extensions::NetworkingConfigServiceFactory::GetForBrowserContext(profile); - const std::string extension_id = - networking_config_service->LookupExtensionIdForHexSsid(hex_ssid); - if (extension_id.empty()) - return nullptr; - std::string extension_name = LookUpExtensionName(profile, extension_id); - if (extension_name.empty()) - return std::unique_ptr< - const ash::NetworkingConfigDelegate::ExtensionInfo>(); - std::unique_ptr<const ash::NetworkingConfigDelegate::ExtensionInfo> - extension_info(new const ash::NetworkingConfigDelegate::ExtensionInfo( - extension_id, extension_name)); - return extension_info; -} - -std::string NetworkingConfigDelegateChromeos::LookUpExtensionName( - content::BrowserContext* context, - std::string extension_id) const { - extensions::ExtensionRegistry* extension_registry = - extensions::ExtensionRegistry::Get(context); - DCHECK(extension_registry); - const extensions::Extension* extension = extension_registry->GetExtensionById( - extension_id, extensions::ExtensionRegistry::ENABLED); - if (extension == nullptr) - return std::string(); - return extension->name(); -} - -} // namespace chromeos
diff --git a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h b/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h deleted file mode 100644 index 901c22e..0000000 --- a/chrome/browser/ui/ash/network/networking_config_delegate_chromeos.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_ASH_NETWORK_NETWORKING_CONFIG_DELEGATE_CHROMEOS_H_ -#define CHROME_BROWSER_UI_ASH_NETWORK_NETWORKING_CONFIG_DELEGATE_CHROMEOS_H_ - -#include <string> - -#include "ash/system/networking_config_delegate.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "content/public/browser/browser_context.h" - -namespace chromeos { - -// A class which allows the ash tray to retrieve extension provided networking -// configuration through the networking config service. -class NetworkingConfigDelegateChromeos : public ash::NetworkingConfigDelegate { - public: - NetworkingConfigDelegateChromeos(); - ~NetworkingConfigDelegateChromeos() override; - - std::unique_ptr<const ExtensionInfo> LookUpExtensionForNetwork( - const std::string& guid) override; - - private: - std::string LookUpExtensionName(content::BrowserContext* context, - std::string extension_id) const; - - DISALLOW_COPY_AND_ASSIGN(NetworkingConfigDelegateChromeos); -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_UI_ASH_NETWORK_NETWORKING_CONFIG_DELEGATE_CHROMEOS_H_
diff --git a/chrome/browser/ui/ash/system_tray_client.cc b/chrome/browser/ui/ash/system_tray_client.cc index 6319937..3d421da 100644 --- a/chrome/browser/ui/ash/system_tray_client.cc +++ b/chrome/browser/ui/ash/system_tray_client.cc
@@ -106,7 +106,7 @@ bool IsArcVpn(const std::string& network_id) { const chromeos::NetworkState* network_state = GetNetworkState(network_id); return network_state && network_state->type() == shill::kTypeVPN && - network_state->vpn_provider_type() == shill::kProviderArcVpn; + network_state->GetVpnProviderType() == shill::kProviderArcVpn; } } // namespace
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm b/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm index 3fb15c9..933db087 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm
@@ -5,8 +5,6 @@ #include "chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.h" #include "base/mac/availability.h" -#import "chrome/browser/ui/cocoa/browser_window_controller.h" -#import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" #import "chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h" #include "components/autofill/core/browser/autofill_popup_delegate.h" #include "components/autofill/core/browser/popup_item_ids.h" @@ -64,13 +62,8 @@ return; if (@available(macOS 10.12.2, *)) { - BrowserWindowController* bwc = [BrowserWindowController - browserWindowControllerForWindow:[container_view() window]]; - TabContentsController* tabContentsController = - [[bwc tabStripController] activeTabContentsController]; - touch_bar_controller_ = - [tabContentsController webTextfieldTouchBarController]; - + touch_bar_controller_ = [WebTextfieldTouchBarController + controllerForWindow:[container_view() window]]; [touch_bar_controller_ showCreditCardAutofillWithController:this]; } } @@ -79,9 +72,8 @@ const std::vector<base::string16>& values, const std::vector<base::string16>& labels) { AutofillPopupControllerImpl::UpdateDataListValues(values, labels); - if (touch_bar_controller_) { + if (touch_bar_controller_) [touch_bar_controller_ invalidateTouchBar]; - } } void AutofillPopupControllerImplMac::Hide() {
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 62e32d6..28824ed 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -78,6 +78,7 @@ #include "chrome/browser/profiles/profile_metrics.h" #include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/repost_form_warning_controller.h" +#include "chrome/browser/resource_coordinator/tab_load_tracker.h" #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h" #include "chrome/browser/search/search.h" #include "chrome/browser/sessions/session_restore.h" @@ -2003,6 +2004,11 @@ new_view->TakeFallbackContentFrom(old_view); } + // TODO(crbug.com/836409): TabLoadTracker should not rely on being notified + // directly about tab contents swaps. + resource_coordinator::TabLoadTracker::Get()->SwapTabContents( + old_contents, new_contents.get()); + int index = tab_strip_model_->GetIndexOfWebContents(old_contents); DCHECK_NE(TabStripModel::kNoTab, index); return tab_strip_model_->ReplaceWebContentsAt(index, std::move(new_contents));
diff --git a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h index 7fe6d64..63a17bb 100644 --- a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h +++ b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h
@@ -12,7 +12,6 @@ #include "base/mac/scoped_nsobject.h" class FullscreenObserver; -@class WebTextfieldTouchBarController; namespace content { class WebContents; @@ -53,8 +52,6 @@ // Reference to the fullscreen window created to display the WebContents // view separately. NSWindow* separateFullscreenWindow_; - - base::scoped_nsobject<WebTextfieldTouchBarController> touchBarController_; } @property(readonly, nonatomic) content::WebContents* webContents; @@ -100,8 +97,6 @@ // widget or back to WebContentsView's widget. - (void)toggleFullscreenWidget:(BOOL)enterFullscreen; -- (WebTextfieldTouchBarController*)webTextfieldTouchBarController; - @end #endif // CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_TAB_CONTENTS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm index 2067c7a..3929fd4 100644 --- a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm +++ b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
@@ -18,7 +18,6 @@ #include "chrome/browser/ui/cocoa/fullscreen_placeholder_view.h" #include "chrome/browser/ui/cocoa/separate_fullscreen_window.h" #import "chrome/browser/ui/cocoa/themed_window.h" -#import "chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h" #include "chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/common/chrome_features.h" @@ -220,8 +219,6 @@ fullscreenObserver_.reset(new FullscreenObserver(self)); [self changeWebContents:contents]; isPopup_ = popup; - touchBarController_.reset([[WebTextfieldTouchBarController alloc] - initWithTabContentsController:self]); } return self; } @@ -241,10 +238,6 @@ [self setView:view]; } -- (NSTouchBar*)makeTouchBar API_AVAILABLE(macos(10.12.2)) { - return [touchBarController_ makeTouchBar]; -} - - (void)ensureContentsVisibleInSuperview:(NSView*)superview { if (!contents_) return; @@ -424,10 +417,6 @@ return isPopup_; } -- (WebTextfieldTouchBarController*)webTextfieldTouchBarController { - return touchBarController_.get(); -} - @end @implementation TabContentsController (SeparateFullscreenWindowDelegate)
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h index a51d2a8d..dc19594c0 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h +++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
@@ -21,6 +21,7 @@ @class CustomWindowControlsView; @class NewTabButtonCocoa; @class TabContentsController; +@class TabControllerCocoa; @class TabViewCocoa; @class TabStripDragController; @class TabStripView;
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm index 19e8228..fea91ee 100644 --- a/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm +++ b/chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.mm
@@ -23,8 +23,6 @@ #import "chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "components/omnibox/browser/vector_icons.h" @@ -132,7 +130,6 @@ // the profile preferences and the back/forward commands. class TouchBarNotificationBridge : public CommandObserver, public BookmarkTabHelperObserver, - public TabStripModelObserver, public content::WebContentsObserver { public: TouchBarNotificationBridge(BrowserWindowDefaultTouchBar* owner, @@ -140,7 +137,6 @@ : owner_(owner), browser_(browser), contents_(nullptr) { TabStripModel* model = browser_->tab_strip_model(); DCHECK(model); - model->AddObserver(this); UpdateWebContents(model->GetActiveWebContents()); } @@ -148,10 +144,6 @@ ~TouchBarNotificationBridge() override { if (contents_) BookmarkTabHelper::FromWebContents(contents_)->RemoveObserver(this); - - TabStripModel* model = browser_->tab_strip_model(); - if (model) - model->RemoveObserver(this); } void UpdateTouchBar() { [[owner_ controller] invalidateTouchBar]; } @@ -182,16 +174,6 @@ [owner_ setIsStarred:starred]; } - // TabStripModelObserver: - void ActiveTabChanged(content::WebContents* old_contents, - content::WebContents* new_contents, - int index, - int reason) override { - UpdateWebContents(new_contents); - contents_ = new_contents; - UpdateTouchBar(); - } - protected: // CommandObserver: void EnabledStateChangedForCommand(int command, bool enabled) override { @@ -215,11 +197,6 @@ [owner_ setIsPageLoading:NO]; } - void WebContentsDestroyed() override { - // Clean up if the web contents is being destroyed. - UpdateWebContents(nullptr); - } - private: BrowserWindowDefaultTouchBar* owner_; // Weak. Browser* browser_; // Weak. @@ -269,6 +246,7 @@ // Creates and returns the search button. - (NSView*)searchTouchBarView API_AVAILABLE(macos(10.12)); + @end @implementation BrowserWindowDefaultTouchBar
diff --git a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h index 9d000d47..6f0e576 100644 --- a/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h +++ b/chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h
@@ -12,6 +12,11 @@ class Browser; @class BrowserWindowDefaultTouchBar; +@class WebTextfieldTouchBarController; + +namespace content { +class WebContents; +} // Provides a touch bar for the browser window. This class implements the // NSTouchBarDelegate and handles the items in the touch bar. @@ -26,12 +31,16 @@ // nil. - (void)invalidateTouchBar; +- (void)updateWebContents:(content::WebContents*)contents; + +- (content::WebContents*)webContents; @end @interface BrowserWindowTouchBarController (ExposedForTesting) - (BrowserWindowDefaultTouchBar*)defaultTouchBar; +- (WebTextfieldTouchBarController*)webTextfieldTouchBar; @end #endif // CHROME_BROWSER_UI_COCOA_TOUCHBAR_BROWSER_WINDOW_TOUCH_BAR_CONTROLLER_H_
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 f31ffbe..43bc4d9e 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
@@ -12,17 +12,72 @@ #import "base/mac/sdk_forward_declarations.h" #include "chrome/browser/ui/browser.h" #import "chrome/browser/ui/cocoa/touchbar/browser_window_default_touch_bar.h" +#import "chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #import "ui/base/cocoa/touch_bar_util.h" -@interface BrowserWindowTouchBarController () { - // The browser associated with the touch bar. - Browser* browser_; // Weak. +class WebContentsNotificationBridge : public TabStripModelObserver, + public content::WebContentsObserver { + public: + WebContentsNotificationBridge(BrowserWindowTouchBarController* owner, + Browser* browser) + : owner_(owner), browser_(browser), contents_(nullptr) { + TabStripModel* model = browser_->tab_strip_model(); + DCHECK(model); + model->AddObserver(this); + UpdateWebContents(model->GetActiveWebContents()); + } + + ~WebContentsNotificationBridge() override { + TabStripModel* model = browser_->tab_strip_model(); + if (model) + model->RemoveObserver(this); + } + + void UpdateWebContents(content::WebContents* new_contents) { + contents_ = new_contents; + Observe(contents_); + + [owner_ updateWebContents:contents_]; + } + + // TabStripModelObserver: + void ActiveTabChanged(content::WebContents* old_contents, + content::WebContents* new_contents, + int index, + int reason) override { + UpdateWebContents(new_contents); + contents_ = new_contents; + } + + content::WebContents* contents() const { return contents_; } + + protected: + // WebContentsObserver: + void WebContentsDestroyed() override { + // Clean up if the web contents is being destroyed. + UpdateWebContents(nullptr); + } + + private: + BrowserWindowTouchBarController* owner_; // Weak. + Browser* browser_; // Weak. + content::WebContents* contents_; // Weak. +}; + +@interface BrowserWindowTouchBarController () { NSWindow* window_; // Weak. + // Used to receive and handle notifications. + std::unique_ptr<WebContentsNotificationBridge> notificationBridge_; + base::scoped_nsobject<BrowserWindowDefaultTouchBar> defaultTouchBar_; + + base::scoped_nsobject<WebTextfieldTouchBarController> webTextfieldTouchBar_; } @end @@ -30,10 +85,17 @@ - (instancetype)initWithBrowser:(Browser*)browser window:(NSWindow*)window { if ((self = [super init])) { + DCHECK(browser); + window_ = window; + + notificationBridge_ = + std::make_unique<WebContentsNotificationBridge>(self, browser); + defaultTouchBar_.reset([[BrowserWindowDefaultTouchBar alloc] initWithBrowser:browser controller:self]); - window_ = window; + webTextfieldTouchBar_.reset( + [[WebTextfieldTouchBarController alloc] initWithController:self]); } return self; @@ -45,9 +107,23 @@ } - (NSTouchBar*)makeTouchBar { + NSTouchBar* touchBar = [webTextfieldTouchBar_ makeTouchBar]; + if (touchBar) + return touchBar; + return [defaultTouchBar_ makeTouchBar]; } +- (void)updateWebContents:(content::WebContents*)contents { + [defaultTouchBar_ updateWebContents:contents]; + [webTextfieldTouchBar_ updateWebContents:contents]; + [self invalidateTouchBar]; +} + +- (content::WebContents*)webContents { + return notificationBridge_->web_contents(); +} + @end @implementation BrowserWindowTouchBarController (ExposedForTesting) @@ -56,4 +132,8 @@ return defaultTouchBar_.get(); } +- (WebTextfieldTouchBarController*)webTextfieldTouchBar { + return webTextfieldTouchBar_.get(); +} + @end
diff --git a/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.h b/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.h index d916ebcd..7e4c5d3 100644 --- a/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.h +++ b/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.h
@@ -25,8 +25,6 @@ - (instancetype)initWithWebContents:(content::WebContents*)webContents controller:(WebTextfieldTouchBarController*)controller; -- (void)initObserver; - - (NSTouchBar*)makeTouchBar API_AVAILABLE(macos(10.12.2)); - (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
diff --git a/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.mm index 85cb010f..0cfeb53 100644 --- a/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.mm +++ b/chrome/browser/ui/cocoa/touchbar/suggested_text_touch_bar_controller.mm
@@ -26,6 +26,10 @@ SuggestedTextTouchBarController* 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) override { if (@available(macOS 10.12.2, *)) { @@ -82,18 +86,15 @@ if ((self = [super init])) { webContents_ = webContents; controller_ = controller; + observer_.reset( + new text_observer::WebContentsTextObserver(webContents_, self)); } return self; } -- (void)initObserver { - observer_.reset( - new text_observer::WebContentsTextObserver(webContents_, self)); -} - - (NSTouchBar*)makeTouchBar { - if (!webContents_->IsFocusedElementEditable()) + if (!webContents_ || !webContents_->IsFocusedElementEditable()) return nil; base::scoped_nsobject<NSTouchBar> touchBar([[ui::NSTouchBar() alloc] init]); @@ -253,7 +254,9 @@ } - (void)setWebContents:(content::WebContents*)webContents { + // TODO(tnijssen): Update the text suggestions when we change web contents. webContents_ = webContents; + observer_->UpdateWebContents(webContents); } - (content::WebContents*)webContents {
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 5237569..dbca4d7e 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
@@ -12,6 +12,7 @@ #import "base/mac/scoped_nsobject.h" #import "ui/base/cocoa/touch_bar_forward_declarations.h" +@class BrowserWindowTouchBarController; @class CreditCardAutofillTouchBarController; @class SuggestedTextTouchBarController; @class TabContentsController; @@ -20,24 +21,32 @@ class AutofillPopupController; } +namespace content { +class WebContents; +} + // Provides a touch bar for the textfields in the WebContents. This class // implements the NSTouchBarDelegate and handles the items in the touch bar. @interface WebTextfieldTouchBarController : NSObject<NSTouchBarDelegate> { - TabContentsController* owner_; // weak. + BrowserWindowTouchBarController* controller_; // weak. base::scoped_nsobject<CreditCardAutofillTouchBarController> autofillTouchBarController_; base::scoped_nsobject<SuggestedTextTouchBarController> suggestedTextTouchBarController_; } ++ (WebTextfieldTouchBarController*)controllerForWindow:(NSWindow*)window; + // Designated initializer. -- (instancetype)initWithTabContentsController:(TabContentsController*)owner; +- (instancetype)initWithController:(BrowserWindowTouchBarController*)controller; - (void)showCreditCardAutofillWithController: (autofill::AutofillPopupController*)controller; - (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 347f606..f51d0af6 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
@@ -8,25 +8,47 @@ #include "base/mac/scoped_nsobject.h" #include "base/mac/sdk_forward_declarations.h" #include "chrome/browser/ui/autofill/autofill_popup_controller.h" +#import "chrome/browser/ui/cocoa/browser_window_controller.h" #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/suggested_text_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 -- (instancetype)initWithTabContentsController:(TabContentsController*)owner { - if ((self = [super init])) { - owner_ = owner; ++ (WebTextfieldTouchBarController*)controllerForWindow:(NSWindow*)window { + if (features::IsViewsBrowserCocoa()) { + BrowserWindowController* bwc = + [BrowserWindowController browserWindowControllerForWindow:window]; + return [[bwc browserWindowTouchBarController] webTextfieldTouchBar]; + } - if (IsSuggestedTextTouchBarEnabled()) { + BrowserView* browser_view = + BrowserView::GetBrowserViewForNativeWindow(window); + if (!browser_view) + return nil; + + BrowserFrameMac* browser_frame = static_cast<BrowserFrameMac*>( + browser_view->frame()->native_browser_frame()); + return [browser_frame->GetTouchBarController() webTextfieldTouchBar]; +} + +- (instancetype)initWithController: + (BrowserWindowTouchBarController*)controller { + if ((self = [super init])) { + controller_ = controller; + + if (base::FeatureList::IsEnabled(features::kSuggestedTextTouchBar)) { suggestedTextTouchBarController_.reset( [[SuggestedTextTouchBarController alloc] - initWithWebContents:[owner_ webContents] + initWithWebContents:[controller_ webContents] controller:self]); - [suggestedTextTouchBarController_ initObserver]; } } @@ -51,13 +73,12 @@ [self invalidateTouchBar]; } -bool IsSuggestedTextTouchBarEnabled() { - return base::FeatureList::IsEnabled(features::kSuggestedTextTouchBar); +- (void)updateWebContents:(content::WebContents*)contents { + [suggestedTextTouchBarController_ setWebContents:contents]; } - (void)invalidateTouchBar { - if ([owner_ respondsToSelector:@selector(setTouchBar:)]) - [owner_ performSelector:@selector(setTouchBar:) withObject:nil]; + [controller_ invalidateTouchBar]; } - (NSTouchBar*)makeTouchBar {
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h index 5e4b775d..36aa01a 100644 --- a/chrome/browser/ui/views/frame/browser_frame.h +++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -120,6 +120,10 @@ // Note that in multi user mode this will upon each call create a new model. ui::MenuModel* GetSystemMenuModel(); + NativeBrowserFrame* native_browser_frame() const { + return native_browser_frame_; + } + private: // Callback for MenuRunner. void OnMenuClosed();
diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.h b/chrome/browser/ui/views/frame/browser_frame_mac.h index d7a48c60..1a1aa8ee 100644 --- a/chrome/browser/ui/views/frame/browser_frame_mac.h +++ b/chrome/browser/ui/views/frame/browser_frame_mac.h
@@ -13,7 +13,8 @@ class BrowserFrame; class BrowserView; -@protocol WindowTouchBarDelegate; +@class BrowserWindowTouchBarController; +@class BrowserWindowTouchBarViewsDelegate; @class ChromeCommandDispatcherDelegate; //////////////////////////////////////////////////////////////////////////////// @@ -25,6 +26,8 @@ public: BrowserFrameMac(BrowserFrame* browser_frame, BrowserView* browser_view); + BrowserWindowTouchBarController* GetTouchBarController() const; + // Overridden from views::NativeWidgetMac: int SheetPositionY() override; void OnWindowFullscreenStateChange() override; @@ -57,7 +60,7 @@ BrowserView* browser_view_; // Weak. Our ClientView. base::scoped_nsobject<ChromeCommandDispatcherDelegate> command_dispatcher_delegate_; - base::scoped_nsprotocol<id<WindowTouchBarDelegate>> touch_bar_delegate_; + base::scoped_nsobject<BrowserWindowTouchBarViewsDelegate> touch_bar_delegate_; DISALLOW_COPY_AND_ASSIGN(BrowserFrameMac); };
diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.mm b/chrome/browser/ui/views/frame/browser_frame_mac.mm index 12c822a..ff426e6b 100644 --- a/chrome/browser/ui/views/frame/browser_frame_mac.mm +++ b/chrome/browser/ui/views/frame/browser_frame_mac.mm
@@ -42,16 +42,18 @@ // Bridge Obj-C class for WindowTouchBarDelegate and // BrowserWindowTouchBarController. -@interface BrowserWindowTouchBarControllerViewsDelegate +@interface BrowserWindowTouchBarViewsDelegate : NSObject<WindowTouchBarDelegate> { Browser* browser_; // Weak. NSWindow* window_; // Weak. base::scoped_nsobject<BrowserWindowTouchBarController> touchBarController_; } +- (BrowserWindowTouchBarController*)touchBarController; + @end -@implementation BrowserWindowTouchBarControllerViewsDelegate +@implementation BrowserWindowTouchBarViewsDelegate - (instancetype)initWithBrowser:(Browser*)browser window:(NSWindow*)window { if ((self = [super init])) { @@ -62,6 +64,10 @@ return self; } +- (BrowserWindowTouchBarController*)touchBarController { + return touchBarController_.get(); +} + - (NSTouchBar*)makeTouchBar API_AVAILABLE(macos(10.12.2)) { if (!touchBarController_) { touchBarController_.reset([[BrowserWindowTouchBarController alloc] @@ -83,6 +89,11 @@ BrowserFrameMac::~BrowserFrameMac() { } +BrowserWindowTouchBarController* BrowserFrameMac::GetTouchBarController() + const { + return [touch_bar_delegate_ touchBarController]; +} + //////////////////////////////////////////////////////////////////////////////// // BrowserFrameMac, views::NativeWidgetMac implementation: @@ -137,10 +148,9 @@ [ns_window setCommandHandler:[[[BrowserWindowCommandHandler alloc] init] autorelease]]; - touch_bar_delegate_.reset( - [[BrowserWindowTouchBarControllerViewsDelegate alloc] - initWithBrowser:browser_view_->browser() - window:ns_window]); + touch_bar_delegate_.reset([[BrowserWindowTouchBarViewsDelegate alloc] + initWithBrowser:browser_view_->browser() + window:ns_window]); [ns_window setWindowTouchBarDelegate:touch_bar_delegate_.get()]; return ns_window.autorelease();
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc index 0b967d6..b7c77b3 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -9,13 +9,13 @@ #include "ash/frame/caption_buttons/frame_back_button.h" // mash-ok #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" // mash-ok #include "ash/frame/default_frame_header.h" // mash-ok -#include "ash/frame/frame_border_hit_test.h" // mash-ok #include "ash/frame/frame_header_util.h" // mash-ok #include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/app_types.h" #include "ash/public/cpp/ash_constants.h" #include "ash/public/cpp/ash_layout_constants.h" #include "ash/public/cpp/ash_switches.h" +#include "ash/public/cpp/frame_border_hit_test.h" #include "ash/public/cpp/window_properties.h" #include "ash/public/interfaces/constants.mojom.h" #include "ash/public/interfaces/window_state_type.mojom.h" @@ -450,19 +450,7 @@ } int BrowserNonClientFrameViewAsh::NonClientHitTest(const gfx::Point& point) { - if (hosted_app_button_container_) { - gfx::Point client_point(point); - View::ConvertPointToTarget(this, hosted_app_button_container_, - &client_point); - if (hosted_app_button_container_->HitTestPoint(client_point)) - return HTCLIENT; - } - - // TODO(sky): figure out how this interaction should work. - const int hit_test = - IsMash() ? HTCLIENT - : ash::FrameBorderNonClientHitTest( - this, back_button_, caption_button_container_, point); + int hit_test = ash::FrameBorderNonClientHitTest(this, point); // When the window is restored we want a large click target above the tabs // to drag the window, so redirect clicks in the tab's shadow to caption. @@ -470,9 +458,10 @@ !frame()->IsFullscreen()) { gfx::Point client_point(point); View::ConvertPointToTarget(this, frame()->client_view(), &client_point); - gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds()); + gfx::Rect tabstrip_shadow_bounds(browser_view()->tabstrip()->bounds()); constexpr int kTabShadowHeight = 4; - if (client_point.y() < tabstrip_bounds.y() + kTabShadowHeight) + tabstrip_shadow_bounds.set_height(kTabShadowHeight); + if (tabstrip_shadow_bounds.Contains(client_point)) return HTCAPTION; }
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc index f25f4f4..10489a28a 100644 --- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -387,8 +387,10 @@ } void GlassBrowserFrameView::UpdateWindowTitle() { - if (ShowCustomTitle() && !frame()->IsFullscreen()) + if (ShowCustomTitle() && !frame()->IsFullscreen()) { + LayoutTitleBar(); window_title_->SchedulePaint(); + } } void GlassBrowserFrameView::ResetWindowControls() {
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 d0c1e87..5404ca81 100644 --- a/chrome/browser/ui/views/frame/hosted_app_button_container.cc +++ b/chrome/browser/ui/views/frame/hosted_app_button_container.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h" #include "chrome/browser/ui/views/page_action/page_action_icon_container_view.h" #include "chrome/browser/ui/views/toolbar/browser_actions_container.h" +#include "ui/base/hit_test.h" #include "ui/compositor/layer_animation_element.h" #include "ui/compositor/layer_animation_sequence.h" #include "ui/compositor/scoped_layer_animation_settings.h" @@ -27,6 +28,7 @@ #include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/layout_provider.h" +#include "ui/views/view_properties.h" #include "ui/views/widget/native_widget_aura.h" namespace { @@ -181,6 +183,8 @@ image_view->SetBorder(views::CreateEmptyBorder( gfx::Insets(kContentSettingIconInteriorPadding))); image_view->disable_animation(); + image_view->SetProperty(views::kHitTestComponentKey, + static_cast<int>(HTCLIENT)); content_setting_views_.push_back(image_view.get()); AddChildView(image_view.release()); } @@ -222,8 +226,16 @@ layout.set_cross_axis_alignment( views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); + content_settings_container_->SetProperty(views::kHitTestComponentKey, + static_cast<int>(HTCLIENT)); AddChildView(content_settings_container_); + + page_action_icon_container_view_->SetProperty(views::kHitTestComponentKey, + static_cast<int>(HTCLIENT)); AddChildView(page_action_icon_container_view_); + + browser_actions_container_->SetProperty(views::kHitTestComponentKey, + static_cast<int>(HTCLIENT)); AddChildView(browser_actions_container_); AddChildView(app_menu_button_);
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 15b8259..3e1f57b 100644 --- a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc +++ b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
@@ -13,16 +13,20 @@ #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/toolbar/app_menu.h" #include "chrome/grit/generated_resources.h" +#include "ui/base/hit_test.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/views/border.h" #include "ui/views/controls/button/menu_button.h" +#include "ui/views/view_properties.h" constexpr int kMenuHighlightFadeDurationMs = 800; HostedAppMenuButton::HostedAppMenuButton(BrowserView* browser_view) : AppMenuButton(this), browser_view_(browser_view) { + SetProperty(views::kHitTestComponentKey, static_cast<int>(HTMENU)); + SetInkDropMode(InkDropMode::ON); // Disable focus ring for consistency with sibling buttons and AppMenuButton. SetFocusPainter(nullptr);
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc index d1178e1d..501feb7 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -284,8 +284,10 @@ } void OpaqueBrowserFrameView::UpdateWindowTitle() { - if (!frame()->IsFullscreen()) + if (!frame()->IsFullscreen() && ShouldShowWindowTitle()) { + Layout(); window_title_->SchedulePaint(); + } } void OpaqueBrowserFrameView::SizeConstraintsChanged() {}
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc index 4c60d9b..29070c510 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -45,6 +45,10 @@ #include "ui/views/widget/widget.h" #include "ui/views/window/non_client_view.h" +#if defined(USE_AURA) +#include "ui/wm/core/window_util.h" +#endif // defined(USE_AURA) + namespace { // Cache the shadow images so that potentially expensive shadow drawing isn't @@ -194,6 +198,12 @@ animator_->SetTargetBounds(bounds); else SetBounds(bounds); + +#if defined(USE_AURA) + // TODO(malaykeshav): Remove this manual snap when we start snapping each + // window to its parent window. See https://crbug.com/863268 for more info. + wm::SnapWindowToPixelBoundary(GetNativeWindow()); +#endif // defined(USE_AURA) } void ShowAnimated() {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc index 96bab85..0d12a623 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc
@@ -37,7 +37,9 @@ #include "ui/views/widget/widget.h" #if defined(USE_AURA) +#include "ui/aura/window.h" #include "ui/native_theme/native_theme_dark_aura.h" +#include "ui/wm/core/window_properties.h" #endif #if defined(USE_X11) @@ -170,6 +172,12 @@ IN_PROC_BROWSER_TEST_P(OmniboxPopupContentsViewTest, PopupAlignment) { views::Widget* popup = CreatePopupForTestQuery(); +#if defined(USE_AURA) + popup_view()->UpdatePopupAppearance(); + EXPECT_TRUE( + popup->GetNativeWindow()->GetProperty(wm::kSnapChildrenToPixelBoundary)); +#endif // defined(USE_AURA) + if (GetParam() == WIDE) { EXPECT_EQ(toolbar()->width(), popup->GetRestoredBounds().width()); } else {
diff --git a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc index 9090944..f7c86340 100644 --- a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
@@ -157,6 +157,10 @@ } void AccountManagerUIHandler::RefreshUI() { + if (!IsJavascriptAllowed()) { + return; + } + FireWebUIListener("accounts-changed"); }
diff --git a/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc b/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc index 2f8cfda..7a4c8be 100644 --- a/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/internet_handler.cc
@@ -187,16 +187,16 @@ return; } - if (network->vpn_provider_type() == shill::kProviderThirdPartyVpn) { + if (network->GetVpnProviderType() == shill::kProviderThirdPartyVpn) { // Request that the third-party VPN provider used by the |network| show a // configuration dialog for it. VpnServiceFactory::GetForBrowserContext(profile_) - ->SendShowConfigureDialogToExtension(network->vpn_provider_id(), + ->SendShowConfigureDialogToExtension(network->vpn_provider()->id, network->name()); return; } - if (network->vpn_provider_type() == shill::kProviderArcVpn) { + if (network->GetVpnProviderType() == shill::kProviderArcVpn) { auto* net_instance = ARC_GET_INSTANCE_FOR_METHOD( arc::ArcServiceManager::Get()->arc_bridge_service()->net(), ConfigureAndroidVpn); @@ -209,7 +209,7 @@ } NET_LOG(ERROR) << "ConfigureThirdPartyVpn: Unsupported VPN type: " - << network->vpn_provider_type() << " For: " << guid; + << network->GetVpnProviderType() << " For: " << guid; } void InternetHandler::RequestArcVpnProviders(const base::ListValue* args) {
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn index e0a40bc..d6e233fa 100644 --- a/chrome/browser/vr/BUILD.gn +++ b/chrome/browser/vr/BUILD.gn
@@ -255,7 +255,6 @@ "ui_test_input.h", "ui_unsupported_mode.h", "vr_export.h", - "vr_features.h", "vr_geometry_util.cc", "vr_geometry_util.h", ] @@ -274,15 +273,18 @@ "//chrome/browser/vr/vector_icons", "//chrome/common:constants", "//components/omnibox/browser", + "//components/rappor/public:public", "//components/security_state/core", "//components/strings", "//components/toolbar", + "//components/toolbar:vector_icons", "//components/ukm/content", "//components/url_formatter", "//components/vector_icons", "//content/public/browser", "//content/public/common", "//device/vr", + "//device/vr/buildflags:buildflags", "//device/vr/public/mojom", "//media", "//net",
diff --git a/chrome/common/extensions/docs/examples/api/fontSettings/css/chrome_shared.css b/chrome/common/extensions/docs/examples/api/fontSettings/css/chrome_shared.css index 656b45d..007d6f440 100644 --- a/chrome/common/extensions/docs/examples/api/fontSettings/css/chrome_shared.css +++ b/chrome/common/extensions/docs/examples/api/fontSettings/css/chrome_shared.css
@@ -74,8 +74,8 @@ } html[dir='rtl'] .favicon-cell.weakrtl { - -webkit-padding-end: 22px; - -webkit-padding-start: 0; + padding-inline-end: 22px; + padding-inline-start: 0; } /* weakrtl for selection drop downs needs to account for the fact that
diff --git a/chrome/common/extensions/docs/examples/api/fontSettings/css/overlay.css b/chrome/common/extensions/docs/examples/api/fontSettings/css/overlay.css index 361938221..432ca62 100644 --- a/chrome/common/extensions/docs/examples/api/fontSettings/css/overlay.css +++ b/chrome/common/extensions/docs/examples/api/fontSettings/css/overlay.css
@@ -94,7 +94,6 @@ } .overlay .page h1 { - -webkit-padding-end: 24px; -webkit-user-select: none; color: #333; /* 120% of the body's font-size of 84% is 16px. This will keep the relative @@ -138,8 +137,8 @@ } .overlay .page .button-strip > button { - -webkit-margin-start: 10px; display: block; + margin-inline-start: 10px; } /* On OSX 10.7, hidden scrollbars may prevent the user from realizing that the
diff --git a/chrome/common/extensions/docs/examples/api/fontSettings/css/uber_shared.css b/chrome/common/extensions/docs/examples/api/fontSettings/css/uber_shared.css index 4fc5b0f50..482451b5 100644 --- a/chrome/common/extensions/docs/examples/api/fontSettings/css/uber_shared.css +++ b/chrome/common/extensions/docs/examples/api/fontSettings/css/uber_shared.css
@@ -3,8 +3,8 @@ * found in the LICENSE file. */ body.uber-frame { - -webkit-margin-start: 155px; color: rgb(48, 57, 66); + margin-inline-start: 155px; } html[dir='rtl'] body.uber-frame { @@ -19,7 +19,7 @@ body.uber-frame #mainview-content .page, body.uber-frame .subpage-sheet-container .page, body.uber-frame > .page { - -webkit-margin-end: 24px; + margin-inline-end: 24px; min-width: 576px; padding-bottom: 20px; padding-top: 55px; @@ -31,7 +31,7 @@ rgba(255, 255, 255, 0.92)); left: 155px; /* <section>s in options currently amount to 638px total, broken up into - * 600px max-width + 18px -webkit-padding-start + 20px -webkit-margin-end + * 600px max-width + 18px padding-inline-start + 20px margin-inline-end * so we mirror this value here so the headers match width and horizontal * alignment when scrolling sideways. */ max-width: 738px; @@ -78,11 +78,11 @@ /* Create a border under the h1 (but before anything that gets appended * to the end of the header). */ body.uber-frame header > h1::after { - -webkit-margin-end: 20px; background-color: #eee; content: ' '; display: block; height: 1px; + margin-inline-end: 20px; position: relative; top: 13px; } @@ -99,10 +99,10 @@ /* Sections are used in options pages, help page and history page. This defines * the section metrics to match the header metrics above. */ body.uber-frame section { - -webkit-padding-start: 18px; margin-bottom: 24px; margin-top: 8px; max-width: 600px; + padding-inline-start: 18px; } body.uber-frame section:last-of-type { @@ -110,7 +110,7 @@ } body.uber-frame section > h3 { - -webkit-margin-start: -18px; + margin-inline-start: -18px; } body.uber-frame section > div:only-of-type {
diff --git a/chrome/common/extensions/docs/examples/api/fontSettings/css/widgets.css b/chrome/common/extensions/docs/examples/api/fontSettings/css/widgets.css index e03bd8b..dee76357 100644 --- a/chrome/common/extensions/docs/examples/api/fontSettings/css/widgets.css +++ b/chrome/common/extensions/docs/examples/api/fontSettings/css/widgets.css
@@ -46,19 +46,19 @@ :-webkit-any(button, input[type='button'], input[type='submit']):not(.custom-appearance):not(.link-button) { - -webkit-padding-end: 10px; - -webkit-padding-start: 10px; + padding-inline-end: 10px; + padding-inline-start: 10px; } select { -webkit-appearance: none; - -webkit-padding-end: 20px; - -webkit-padding-start: 6px; /* OVERRIDE */ background-image: url('../images/select.png'), -webkit-linear-gradient(#ededed, #ededed 38%, #dedede); background-position: right center; background-repeat: no-repeat; + padding-inline-end: 20px; + padding-inline-start: 6px; } html[dir='rtl'] select { @@ -292,9 +292,9 @@ } :-webkit-any(.checkbox, .radio) label input ~ span { - -webkit-margin-start: 0.6em; /* Make sure long spans wrap at the same horizontal position they start. */ display: block; + margin-inline-start: 0.6em; } :-webkit-any(.checkbox, .radio) label:hover {
diff --git a/chrome/common/extensions/docs/examples/api/fontSettings/options.html b/chrome/common/extensions/docs/examples/api/fontSettings/options.html index 1d378671..3e40b67 100644 --- a/chrome/common/extensions/docs/examples/api/fontSettings/options.html +++ b/chrome/common/extensions/docs/examples/api/fontSettings/options.html
@@ -16,8 +16,8 @@ <link rel="stylesheet" href="slider.css"> <style> body.uber-frame { - -webkit-margin-start: 18px; - -webkit-margin-end: 30px; + margin-inline-start: 18px; + margin-inline-end: 30px; } body.uber-frame section { @@ -29,8 +29,8 @@ } body.uber-frame header { - -webkit-padding-start: 18px; left: 0; + padding-inline-start: 18px; right: 0; } @@ -65,7 +65,7 @@ } .font-settings-div { - -webkit-margin-end: 5px; + margin-inline-end: 5px; width: 180px; } @@ -128,13 +128,13 @@ } #footer > button { - -webkit-padding-start: 9px; - -webkit-padding-end: 9px; + padding-inline-start: 9px; + padding-inline-end: 9px; } #footer > #apply-settings { - -webkit-padding-start: 17px; - -webkit-padding-end: 17px; + padding-inline-start: 17px; + padding-inline-end: 17px; } #apply-settings:enabled {
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/plugin_list.css b/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/plugin_list.css index 9d178e5..acb72a76 100644 --- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/plugin_list.css +++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/plugin_list.css
@@ -1,8 +1,6 @@ -/* -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. -*/ +/* 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. */ body { font-family: Helvetica, sans-serif; @@ -38,7 +36,7 @@ .plugin-description { display: inline-block; - -webkit-padding-start: 7px; + padding-inline-start: 7px; width: auto; overflow: hidden; text-overflow: ellipsis; @@ -76,8 +74,8 @@ } .column-headers { - -webkit-margin-start: 17px; display: -webkit-box; + margin-inline-start: 17px; } .column-headers > div {
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/rule_list.css b/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/rule_list.css index b67157b..2d6c9c1e 100644 --- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/rule_list.css +++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/css/rule_list.css
@@ -1,13 +1,11 @@ -/* -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. -*/ +/* 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. */ .rule-pattern { -webkit-box-flex: 1; - -webkit-margin-end: 10px; - -webkit-margin-start: 14px; + margin-inline-end: 10px; + margin-inline-start: 14px; } .rule-behavior {
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/chrome_shared.css b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/chrome_shared.css index fa70aa20..dac22eb 100644 --- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/chrome_shared.css +++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/chrome_shared.css
@@ -1,3 +1,7 @@ +/* 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. */ + /* Styles common to WebUI pages that share the options pages style */ body { cursor: default; @@ -13,7 +17,6 @@ } #navbar-content-title { - -webkit-padding-end: 24px; -webkit-user-select: none; color: #53637d; cursor: pointer; @@ -21,6 +24,7 @@ font-weight: normal; margin: 0; padding-bottom: 14px; + padding-inline-end: 24px; padding-top: 13px; text-align: end; text-shadow: white 0 1px 2px; @@ -40,9 +44,9 @@ } #navbar-container { - -webkit-border-end: 1px solid #c6c9ce; background: -webkit-linear-gradient(rgba(234, 238, 243, 0.2), #eaeef3), -webkit-linear-gradient(left, #eaeef3, #eaeef3 97%, #d3d7db); + border-inline-end: 1px solid #c6c9ce; position: fixed; bottom: 0; /* We set both left and right for the sake of RTL. */ @@ -78,9 +82,9 @@ font-size: 105%; outline: none; padding: 7px 0; + padding-inline-end: 24px; text-align: end; text-shadow: white 0 1px 1px; - -webkit-padding-end: 24px; } .navbar-item:focus { @@ -99,10 +103,10 @@ #mainview { -webkit-box-align: stretch; - -webkit-padding-start: 216px; margin: 0; position: absolute; left: 0; + padding-inline-start: 216px; right: 0; top: 0; bottom: 0; @@ -110,7 +114,7 @@ } html.hide-menu #mainview { - -webkit-padding-start: 0; + padding-inline-start: 0; } #mainview-content { @@ -216,8 +220,8 @@ } html[dir='rtl'] .favicon-cell.weakrtl { - -webkit-padding-end: 22px; - -webkit-padding-start: 0; + padding-inline-end: 22px; + padding-inline-start: 0; } /* weakrtl for selection drop downs needs to account for the fact that @@ -242,7 +246,6 @@ } .page h1 { - -webkit-padding-end: 24px; -webkit-user-select: none; border-bottom: 1px solid #eeeeee; color: #53637d; @@ -250,6 +253,7 @@ font-weight: normal; margin: 0; padding-bottom: 4px; + padding-inline-end: 24px; padding-top: 13px; text-shadow: white 0 1px 2px; }
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/select.css b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/select.css index ba951e5..24de2aaf 100644 --- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/select.css +++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/css/select.css
@@ -9,8 +9,6 @@ -webkit-appearance: button; -webkit-border-radius: 2px; -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - -webkit-padding-end: 20px; - -webkit-padding-start: 2px; -webkit-user-select: none; background-image: url("../images/select.png"), -webkit-linear-gradient(#fafafa, #f4f4f4 40%, #e5e5e5); @@ -22,6 +20,8 @@ margin: 0; overflow: hidden; padding-top: 2px; + padding-inline-end: 20px; + padding-inline-start: 2px; padding-bottom: 2px; text-overflow: ellipsis; white-space: nowrap;
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/options/css/list.css b/chrome/common/extensions/docs/examples/extensions/plugin_settings/options/css/list.css index cee1b08..4ff7b90b 100644 --- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/options/css/list.css +++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/options/css/list.css
@@ -62,8 +62,8 @@ list .deletable-item > :first-child { -webkit-box-align: center; -webkit-box-flex: 1; - -webkit-padding-end: 5px; display: -webkit-box; + padding-inline-end: 5px; } list .close-button {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 87ee53a..d35b7f9 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1726,7 +1726,7 @@ "../browser/ui/ash/launcher/chrome_launcher_controller_test_util.h", "../browser/ui/ash/multi_user/test_multi_user_window_manager.cc", "../browser/ui/ash/multi_user/test_multi_user_window_manager.h", - "../browser/ui/ash/network/networking_config_delegate_chromeos_browsertest.cc", + "../browser/ui/ash/network/networking_config_chromeos_browsertest.cc", "../browser/ui/ash/shelf_browsertest.cc", "../browser/ui/ash/system_tray_client_browsertest.cc", "../browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc", @@ -2922,6 +2922,7 @@ "//base:base_java", "//chrome/android:app_hooks_java", "//chrome/android:chrome_java", + "//components/favicon/core/test:test_support", "//components/gcm_driver/instance_id/android:instance_id_driver_java", "//components/gcm_driver/instance_id/android:instance_id_driver_test_support_java", "//content/public/android:content_java",
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index 8e9edfd..7b9416a 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -138,6 +138,8 @@ 'ChromeDriverTest.testGetCurrentWindowHandle', 'ChromeDriverTest.testStartStop', 'ChromeDriverTest.testSendCommand*', + # https://crbug.com/867511 + 'ChromeDriverTest.testWindowMaximize', # LaunchApp is an obsolete API. 'ChromeExtensionsCapabilityTest.testCanLaunchApp', # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2278
diff --git a/chrome/test/data/autofill/dynamic_form_element_invalid.html b/chrome/test/data/autofill/dynamic_form_element_invalid.html new file mode 100644 index 0000000..dae67e09 --- /dev/null +++ b/chrome/test/data/autofill/dynamic_form_element_invalid.html
@@ -0,0 +1,60 @@ +<!-- A page that is used to test that a dynamic form fill feature works properly. --> +<body> + <form name="addr1.1" id="form1" action="https://example.com/" method="post"> + Name: <input type="text" name="firstname" id="firstname" autocomplete="given-name"><br> + <input type="text" name="firstname" id="firstname2" autocomplete="given-name" style="display: none"><br> + Address: <input type="text" name="address1" id="address1"><br> + City: <input type="text" name="city" id="city"><br> + <input type="text" name="state_us" id="state_us" style="display: none;" autocomplete="region"><br> + Zip: <input name="zip" id="zip"> <br> + Country: <select name="country" id="country" onchange="CountryChanged()"> + <option value="CA">Canada</option> + <option value="US">United States</option> + </select> <br> + Company: <input name="company" id="company"> <br> + Email: <input name="email" id="email"> <br> + Phone: <input name="phone" id="phone"> <br> + <input type="reset" value="Reset"> + <input type="submit" value="Submit" id="profile_submit"> + </form> +</body> + +<script> + + +var notify_on_address_input_change = false; +var address_input_changed = false; + +function CountryChanged() { + // Reset the value of the address field. + var address1 = document.getElementById('address1'); + address1.value = ''; + address1.onchange = function() { + if (notify_on_address_input_change) + window.domAutomationController.send(address1.value != ''); + else + address_input_changed = true; + } + + // Change the element that triggered the autofill. Remove it, and make another + // field visible. This is to test if the autofill can handle the case where + // the clicked on element is no longer valid. + var first_name_input = document.getElementById("firstname"); + first_name_input.parentNode.removeChild(first_name_input); + + var name_later = document.getElementById("firstname2"); + name_later.removeAttribute('style'); +} + + +function hasRefilled() { + var address1 = document.getElementById('address1'); + if (address1 && address_input_changed) { + window.domAutomationController.send(address1.value != ''); + } else { + notify_on_address_input_change = true; + } +} + +</script> +
diff --git a/chrome/test/data/autofill/dynamic_form_element_invalid_noname_form.html b/chrome/test/data/autofill/dynamic_form_element_invalid_noname_form.html new file mode 100644 index 0000000..e0020c8 --- /dev/null +++ b/chrome/test/data/autofill/dynamic_form_element_invalid_noname_form.html
@@ -0,0 +1,60 @@ +<!-- A page that is used to test that a dynamic form fill feature works properly. --> +<body> + <form id="form1" action="https://example.com/" method="post"> + Name: <input type="text" name="firstname" id="firstname" autocomplete="given-name"><br> + <input type="text" name="firstname" id="firstname2" autocomplete="given-name" style="display: none"><br> + Address: <input type="text" name="address1" id="address1"><br> + City: <input type="text" name="city" id="city"><br> + <input type="text" name="state_us" id="state_us" style="display: none;" autocomplete="region"><br> + Zip: <input name="zip" id="zip"> <br> + Country: <select name="country" id="country" onchange="CountryChanged()"> + <option value="CA">Canada</option> + <option value="US">United States</option> + </select> <br> + Company: <input name="company" id="company"> <br> + Email: <input name="email" id="email"> <br> + Phone: <input name="phone" id="phone"> <br> + <input type="reset" value="Reset"> + <input type="submit" value="Submit" id="profile_submit"> + </form> +</body> + +<script> + + +var notify_on_address_input_change = false; +var address_input_changed = false; + +function CountryChanged() { + // Reset the value of the address field. + var address1 = document.getElementById('address1'); + address1.value = ''; + address1.onchange = function() { + if (notify_on_address_input_change) + window.domAutomationController.send(address1.value != ''); + else + address_input_changed = true; + } + + // Change the element that triggered the autofill. Remove it, and make another + // field visible. This is to test if the autofill can handle the case where + // the clicked on element is no longer valid. + var first_name_input = document.getElementById("firstname"); + first_name_input.parentNode.removeChild(first_name_input); + + var name_later = document.getElementById("firstname2"); + name_later.removeAttribute('style'); +} + + +function hasRefilled() { + var address1 = document.getElementById('address1'); + if (address1 && address_input_changed) { + window.domAutomationController.send(address1.value != ''); + } else { + notify_on_address_input_change = true; + } +} + +</script> +
diff --git a/chrome/test/data/autofill/dynamic_form_element_invalid_unowned.html b/chrome/test/data/autofill/dynamic_form_element_invalid_unowned.html new file mode 100644 index 0000000..04bf4132 --- /dev/null +++ b/chrome/test/data/autofill/dynamic_form_element_invalid_unowned.html
@@ -0,0 +1,60 @@ +<!-- A page that is used to test that a dynamic form fill feature works properly. --> +<body> + Name: + <input type="text" name="firstname" id="firstname0" autocomplete="given-name" style="display: none"><br> + <input type="text" name="firstname" id="firstname" autocomplete="given-name"><br> + <input type="text" name="firstname" id="firstname2" autocomplete="given-name" style="display: none"><br> + Address: <input type="text" name="address1" id="address1"><br> + City: <input type="text" name="city" id="city"><br> + <input type="text" name="state_us" id="state_us" style="display: none;" autocomplete="region"><br> + Zip: <input name="zip" id="zip"> <br> + Country: <select name="country" id="country" onchange="CountryChanged()"> + <option value="CA">Canada</option> + <option value="US">United States</option> + </select> <br> + Company: <input name="company" id="company"> <br> + Email: <input name="email" id="email"> <br> + Phone: <input name="phone" id="phone"> <br> + <input type="reset" value="Reset"> + <input type="submit" value="Submit" id="profile_submit"> +</body> + +<script> + + +var notify_on_address_input_change = false; +var address_input_changed = false; + +function CountryChanged() { + // Reset the value of the address field. + var address1 = document.getElementById('address1'); + address1.value = ''; + address1.onchange = function() { + if (notify_on_address_input_change) + window.domAutomationController.send(address1.value != ''); + else + address_input_changed = true; + } + + // Change the element that triggered the autofill. Remove it, and make another + // field visible. This is to test if the autofill can handle the case where + // the clicked on element is no longer valid. + var first_name_input = document.getElementById("firstname"); + first_name_input.parentNode.removeChild(first_name_input); + + var name_later = document.getElementById("firstname2"); + name_later.removeAttribute('style'); +} + + +function hasRefilled() { + var address1 = document.getElementById('address1'); + if (address1 && address_input_changed) { + window.domAutomationController.send(address1.value != ''); + } else { + notify_on_address_input_change = true; + } +} + +</script> +
diff --git a/chrome/test/data/extensions/networking_config_delegate/background.js b/chrome/test/data/extensions/networking_config/background.js similarity index 100% rename from chrome/test/data/extensions/networking_config_delegate/background.js rename to chrome/test/data/extensions/networking_config/background.js
diff --git a/chrome/test/data/extensions/networking_config_delegate/manifest.json b/chrome/test/data/extensions/networking_config/manifest.json similarity index 74% rename from chrome/test/data/extensions/networking_config_delegate/manifest.json rename to chrome/test/data/extensions/networking_config/manifest.json index 9ff003e..6f5b0dda 100644 --- a/chrome/test/data/extensions/networking_config_delegate/manifest.json +++ b/chrome/test/data/extensions/networking_config/manifest.json
@@ -1,5 +1,5 @@ { - "name": "NetworkingConfigDelegate test extension", + "name": "NetworkingConfig test extension", "version": "0.1", "manifest_version": 2, "background": {
diff --git a/chrome/test/data/notifications/android_test.html b/chrome/test/data/notifications/android_test.html index bede1c2..bc255054 100644 --- a/chrome/test/data/notifications/android_test.html +++ b/chrome/test/data/notifications/android_test.html
@@ -39,6 +39,17 @@ } document.title = message; } + + // Some tests require a count of how frequently they were invoked. + var message_counts = {} + function addCountAndSendToTest(message) { + if (message in message_counts) { + message_counts[message]++; + } else { + message_counts[message] = 1; + } + document.title = message + ': ' + message_counts[message]; + } </script> </body> </html>
diff --git a/chrome/test/data/webui/settings/personalization_options_test.js b/chrome/test/data/webui/settings/personalization_options_test.js index 1495b4c..845d0332 100644 --- a/chrome/test/data/webui/settings/personalization_options_test.js +++ b/chrome/test/data/webui/settings/personalization_options_test.js
@@ -89,10 +89,13 @@ testElement.unifiedConsentEnabled = false; Polymer.dom.flush(); assertEquals( - 8, + 7, testElement.root.querySelectorAll('settings-toggle-button').length); testElement.unifiedConsentEnabled = true; Polymer.dom.flush(); + assertEquals( + 8, + testElement.root.querySelectorAll('settings-toggle-button').length); }); }); }
diff --git a/chromecast/net/connectivity_checker.cc b/chromecast/net/connectivity_checker.cc index 5e9679e..74d18b1 100644 --- a/chromecast/net/connectivity_checker.cc +++ b/chromecast/net/connectivity_checker.cc
@@ -36,8 +36,8 @@ scoped_refptr<ConnectivityChecker> ConnectivityChecker::Create( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, net::URLRequestContextGetter* url_request_context_getter) { - return base::MakeRefCounted<ConnectivityCheckerImpl>( - task_runner, url_request_context_getter); + return ConnectivityCheckerImpl::Create(task_runner, + url_request_context_getter); } } // namespace chromecast
diff --git a/chromecast/net/connectivity_checker_impl.cc b/chromecast/net/connectivity_checker_impl.cc index b2acca1..297398f 100644 --- a/chromecast/net/connectivity_checker_impl.cc +++ b/chromecast/net/connectivity_checker_impl.cc
@@ -56,20 +56,30 @@ } // namespace +// static +scoped_refptr<ConnectivityCheckerImpl> ConnectivityCheckerImpl::Create( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + net::URLRequestContextGetter* url_request_context_getter) { + DCHECK(task_runner); + + auto connectivity_checker = + base::WrapRefCounted(new ConnectivityCheckerImpl(task_runner)); + task_runner->PostTask( + FROM_HERE, + base::BindOnce(&ConnectivityCheckerImpl::Initialize, connectivity_checker, + base::RetainedRef(url_request_context_getter))); + return connectivity_checker; +} + ConnectivityCheckerImpl::ConnectivityCheckerImpl( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - net::URLRequestContextGetter* url_request_context_getter) + scoped_refptr<base::SingleThreadTaskRunner> task_runner) : ConnectivityChecker(), - task_runner_(task_runner), + task_runner_(std::move(task_runner)), connected_(false), connection_type_(net::NetworkChangeNotifier::CONNECTION_NONE), check_errors_(0), network_changed_pending_(false) { DCHECK(task_runner_.get()); - - task_runner->PostTask( - FROM_HERE, base::BindOnce(&ConnectivityCheckerImpl::Initialize, this, - base::RetainedRef(url_request_context_getter))); } void ConnectivityCheckerImpl::Initialize(
diff --git a/chromecast/net/connectivity_checker_impl.h b/chromecast/net/connectivity_checker_impl.h index 0626d459..9b505b91 100644 --- a/chromecast/net/connectivity_checker_impl.h +++ b/chromecast/net/connectivity_checker_impl.h
@@ -34,8 +34,8 @@ public net::NetworkChangeNotifier::NetworkChangeObserver { public: // Connectivity checking and initialization will run on task_runner. - explicit ConnectivityCheckerImpl( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + static scoped_refptr<ConnectivityCheckerImpl> Create( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, net::URLRequestContextGetter* url_request_context_getter); // ConnectivityChecker implementation: @@ -43,6 +43,8 @@ void Check() override; protected: + explicit ConnectivityCheckerImpl( + scoped_refptr<base::SingleThreadTaskRunner> task_runner); ~ConnectivityCheckerImpl() override; private:
diff --git a/chromeos/network/auto_connect_handler.cc b/chromeos/network/auto_connect_handler.cc index 5cb72b3..010e8a6 100644 --- a/chromeos/network/auto_connect_handler.cc +++ b/chromeos/network/auto_connect_handler.cc
@@ -352,7 +352,6 @@ continue; const bool is_managed = - !network->profile_path().empty() && !network->guid().empty() && managed_configuration_handler_->FindPolicyByGuidAndProfile( network->guid(), network->profile_path(), nullptr /* onc_source */); if (is_managed) @@ -376,7 +375,6 @@ false, false, 0, &networks); for (const NetworkState* network : networks) { const bool is_managed = - !network->profile_path().empty() && !network->guid().empty() && managed_configuration_handler_->FindPolicyByGuidAndProfile( network->guid(), network->profile_path(), nullptr /* onc_source */); if (is_managed)
diff --git a/chromeos/network/managed_network_configuration_handler_impl.cc b/chromeos/network/managed_network_configuration_handler_impl.cc index 37d18661..539af08 100644 --- a/chromeos/network/managed_network_configuration_handler_impl.cc +++ b/chromeos/network/managed_network_configuration_handler_impl.cc
@@ -778,16 +778,19 @@ const std::string& guid, const std::string& profile_path, ::onc::ONCSource* onc_source) const { + if (profile_path.empty()) + return nullptr; + const NetworkProfile* profile = network_profile_handler_->GetProfileForPath(profile_path); if (!profile) { NET_LOG_ERROR("Profile path unknown:" + profile_path, guid); - return NULL; + return nullptr; } const Policies* policies = GetPoliciesForProfile(*profile); if (!policies) - return NULL; + return nullptr; const base::DictionaryValue* policy = GetByGUID(policies->per_network_config, guid); @@ -816,7 +819,6 @@ // Check if the network is managed. Managed networks are always allowed. bool is_managed = - !profile_path.empty() && FindPolicyByGuidAndProfile(guid, profile_path, nullptr /* onc_source */); if (is_managed) return false;
diff --git a/chromeos/network/network_connect.cc b/chromeos/network/network_connect.cc index 2088575..fa12b2c0 100644 --- a/chromeos/network/network_connect.cc +++ b/chromeos/network/network_connect.cc
@@ -139,7 +139,7 @@ if (network->type() == shill::kTypeVPN) { // Third-party VPNs handle configuration UI themselves. - if (network->vpn_provider_type() != shill::kProviderThirdPartyVpn) + if (network->GetVpnProviderType() != shill::kProviderThirdPartyVpn) delegate_->ShowNetworkConfigure(network_id); return; }
diff --git a/chromeos/network/network_connection_handler_impl.cc b/chromeos/network/network_connection_handler_impl.cc index 3218b39..72aa32cd 100644 --- a/chromeos/network/network_connection_handler_impl.cc +++ b/chromeos/network/network_connection_handler_impl.cc
@@ -461,11 +461,9 @@ service_properties.GetStringWithoutPathExpansion(shill::kProfileProperty, &profile); ::onc::ONCSource onc_source = onc::ONC_SOURCE_NONE; - const base::DictionaryValue* policy = nullptr; - if (!profile.empty()) { - policy = managed_configuration_handler_->FindPolicyByGuidAndProfile( - guid, profile, &onc_source); - } + const base::DictionaryValue* policy = + managed_configuration_handler_->FindPolicyByGuidAndProfile(guid, profile, + &onc_source); if (type == shill::kTypeWifi) { const base::Value* hex_ssid_value = service_properties.FindKeyOfType(
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc index ea00e84..328707382 100644 --- a/chromeos/network/network_state.cc +++ b/chromeos/network/network_state.cc
@@ -175,7 +175,7 @@ } return true; } else if (key == shill::kProviderProperty) { - std::string vpn_provider_type; + std::string vpn_provider_type, vpn_provider_id; const base::DictionaryValue* dict; if (!value.GetAsDictionary(&dict) || !dict->GetStringWithoutPathExpansion(shill::kTypeProperty, @@ -189,15 +189,12 @@ // If the network uses a third-party or Arc VPN provider, // |shill::kHostProperty| contains the extension ID or Arc package name. if (!dict->GetStringWithoutPathExpansion(shill::kHostProperty, - &vpn_provider_id_)) { + &vpn_provider_id)) { NET_LOG(ERROR) << "Failed to parse " << path() << "." << key; return false; } - } else { - vpn_provider_id_.clear(); } - - vpn_provider_type_ = vpn_provider_type; + SetVpnProvider(vpn_provider_id, vpn_provider_type); return true; } else if (key == shill::kTetheringProperty) { return GetStringValue(key, value, &tethering_state_); @@ -248,17 +245,17 @@ dictionary->SetKey(shill::kDeviceProperty, base::Value(device_path())); // VPN properties. - if (NetworkTypePattern::VPN().MatchesType(type())) { + if (NetworkTypePattern::VPN().MatchesType(type()) && vpn_provider()) { // Shill sends VPN provider properties in a nested dictionary. |dictionary| // must replicate that nested structure. std::unique_ptr<base::DictionaryValue> provider_property( new base::DictionaryValue); - provider_property->SetKey(shill::kTypeProperty, - base::Value(vpn_provider_type_)); - if (vpn_provider_type_ == shill::kProviderThirdPartyVpn || - vpn_provider_type_ == shill::kProviderArcVpn) { + std::string provider_type = vpn_provider()->type; + provider_property->SetKey(shill::kTypeProperty, base::Value(provider_type)); + if (provider_type == shill::kProviderThirdPartyVpn || + provider_type == shill::kProviderArcVpn) { provider_property->SetKey(shill::kHostProperty, - base::Value(vpn_provider_id_)); + base::Value(vpn_provider()->id)); } dictionary->SetWithoutPathExpansion(shill::kProviderProperty, std::move(provider_property)); @@ -336,6 +333,22 @@ return gurl; } +void NetworkState::SetCaptivePortalProvider(const std::string& id, + const std::string& name) { + if (id.empty()) { + captive_portal_provider_ = nullptr; + return; + } + if (!captive_portal_provider_) + captive_portal_provider_ = std::make_unique<CaptivePortalProviderInfo>(); + captive_portal_provider_->id = id; + captive_portal_provider_->name = name; +} + +std::string NetworkState::GetVpnProviderType() const { + return vpn_provider_ ? vpn_provider_->type : std::string(); +} + bool NetworkState::RequiresActivation() const { return type() == shill::kTypeCellular && activation_state() != shill::kActivationStateActivated && @@ -447,16 +460,6 @@ guid_ = guid; } -bool NetworkState::UpdateName(const base::DictionaryValue& properties) { - std::string updated_name = - shill_property_util::GetNameFromProperties(path(), properties); - if (updated_name != name()) { - set_name(updated_name); - return true; - } - return false; -} - std::string NetworkState::GetErrorState() const { if (ErrorIsValid(error())) return error(); @@ -500,4 +503,29 @@ return new_state; } +// Private methods. + +bool NetworkState::UpdateName(const base::DictionaryValue& properties) { + std::string updated_name = + shill_property_util::GetNameFromProperties(path(), properties); + if (updated_name != name()) { + set_name(updated_name); + return true; + } + return false; +} + +void NetworkState::SetVpnProvider(const std::string& id, + const std::string& type) { + // |type| is required but |id| is only set for ThirdParty and Arc VPNs. + if (type.empty()) { + vpn_provider_ = nullptr; + return; + } + if (!vpn_provider_) + vpn_provider_ = std::make_unique<VpnProviderInfo>(); + vpn_provider_->id = id; + vpn_provider_->type = type; +} + } // namespace chromeos
diff --git a/chromeos/network/network_state.h b/chromeos/network/network_state.h index 4aedc83..4c91c35 100644 --- a/chromeos/network/network_state.h +++ b/chromeos/network/network_state.h
@@ -20,7 +20,7 @@ namespace base { class DictionaryValue; class Value; -} +} // namespace base namespace chromeos { @@ -39,6 +39,20 @@ explicit NetworkState(const std::string& path); ~NetworkState() override; + struct CaptivePortalProviderInfo { + // The id used by chrome to identify the provider (i.e. an extension id). + std::string id; + // The display name for the captive portal provider (i.e. extension name). + std::string name; + }; + + struct VpnProviderInfo { + // The id used by chrome to identify the provider (i.e. an extension id). + std::string id; + // The VPN type, provided by the VPN provider/extension. + std::string type; + }; + // ManagedState overrides // If you change this method, update GetProperties too. bool PropertyChanged(const std::string& key, @@ -81,6 +95,10 @@ bool connectable() const { return connectable_; } void set_connectable(bool connectable) { connectable_ = connectable; } bool is_captive_portal() const { return is_captive_portal_; } + const CaptivePortalProviderInfo* captive_portal_provider() const { + return captive_portal_provider_.get(); + } + void SetCaptivePortalProvider(const std::string& id, const std::string& name); int signal_strength() const { return signal_strength_; } void set_signal_strength(int signal_strength) { signal_strength_ = signal_strength; @@ -91,9 +109,7 @@ const std::vector<uint8_t>& raw_ssid() const { return raw_ssid_; } // Cellular property accessors - const std::string& network_technology() const { - return network_technology_; - } + const std::string& network_technology() const { return network_technology_; } const std::string& activation_type() const { return activation_type_; } const std::string& activation_state() const { return activation_state_; } const std::string& roaming() const { return roaming_; } @@ -102,8 +118,8 @@ const std::string& tethering_state() const { return tethering_state_; } // VPN property accessors - const std::string& vpn_provider_type() const { return vpn_provider_type_; } - const std::string& vpn_provider_id() const { return vpn_provider_id_; } + const VpnProviderInfo* vpn_provider() const { return vpn_provider_.get(); } + std::string GetVpnProviderType() const; // Tether accessors and setters. int battery_percentage() const { return battery_percentage_; } @@ -189,6 +205,8 @@ // Returns true if |name_| changes. bool UpdateName(const base::DictionaryValue& properties); + void SetVpnProvider(const std::string& id, const std::string& type); + // Set to true if the network is a member of Manager.Services. bool visible_ = false; @@ -196,7 +214,7 @@ // Instead use NetworkConfigurationHandler::GetProperties() to asynchronously // request properties from Shill. std::string security_class_; - std::string eap_method_; // Needed for WiFi EAP networks + std::string eap_method_; // Needed for WiFi EAP networks std::string eap_key_mgmt_; // Needed for identifying Dynamic WEP networks std::string device_path_; std::string guid_; @@ -222,6 +240,7 @@ // Wireless properties, used for icons and Connect logic. bool connectable_ = false; bool is_captive_portal_ = false; + std::unique_ptr<CaptivePortalProviderInfo> captive_portal_provider_; int signal_strength_ = 0; std::string bssid_; // For ARC int frequency_ = 0; // For ARC @@ -236,10 +255,9 @@ std::string tethering_state_; // VPN properties, used to construct the display name and to show the correct - // configuration dialog. - std::string vpn_provider_type_; - // Extension ID or Arc package name for extension or Arc provider VPNs. - std::string vpn_provider_id_; + // configuration dialog. The id is the Extension ID or Arc package name for + // extension or Arc provider VPNs. + std::unique_ptr<VpnProviderInfo> vpn_provider_; // Tether properties. std::string carrier_;
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc index d97792db..2d071e5 100644 --- a/chromeos/network/network_state_handler.cc +++ b/chromeos/network/network_state_handler.cc
@@ -27,7 +27,6 @@ #include "chromeos/network/network_device_handler.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_handler_callbacks.h" -#include "chromeos/network/network_state.h" #include "chromeos/network/network_state_handler_observer.h" #include "chromeos/network/tether_constants.h" #include "third_party/cros_system_api/dbus/service_constants.h" @@ -938,6 +937,38 @@ shill_property_handler_->SetCheckPortalList(check_portal_list); } +void NetworkStateHandler::SetCaptivePortalProviderForHexSsid( + const std::string& hex_ssid, + const std::string& provider_id, + const std::string& provider_name) { + NET_LOG(EVENT) << "SetCaptivePortalProviderForHexSsid: " << hex_ssid + << " -> (" << provider_id << ", " << provider_name << ")"; + // NetworkState hex SSIDs are always uppercase. + std::string hex_ssid_uc = hex_ssid; + transform(hex_ssid_uc.begin(), hex_ssid_uc.end(), hex_ssid_uc.begin(), + toupper); + if (provider_id.empty()) { + hex_ssid_to_captive_portal_provider_map_.erase(hex_ssid_uc); + } else { + NetworkState::CaptivePortalProviderInfo provider_info; + provider_info.id = provider_id; + provider_info.name = provider_name; + hex_ssid_to_captive_portal_provider_map_[hex_ssid_uc] = + std::move(provider_info); + } + // When a new entry is added or removed from the map, check all networks + // for a matching hex SSID and update the provider info. (This should occur + // infrequently). New networks will be updated when added. + for (auto& managed : network_list_) { + NetworkState* network = managed->AsNetworkState(); + if (network->GetHexSsid() == hex_ssid_uc) { + NET_LOG(EVENT) << "Setting captive portal provider for network: " + << network->guid() << " = " << provider_id; + network->SetCaptivePortalProvider(provider_id, provider_name); + } + } +} + void NetworkStateHandler::SetWakeOnLanEnabled(bool enabled) { NET_LOG_EVENT("SetWakeOnLanEnabled", enabled ? "true" : "false"); shill_property_handler_->SetWakeOnLanEnabled(enabled); @@ -1134,7 +1165,10 @@ network_property_updated = true; } network_property_updated |= network->InitialPropertiesReceived(properties); + UpdateGuid(network); + UpdateCaptivePortalProvider(network); + network_list_sorted_ = false; // Notify observers of NetworkState changes. @@ -1472,9 +1506,9 @@ } // Ensure that the NetworkState has a valid GUID. std::string guid; - SpecifierGuidMap::iterator iter = specifier_guid_map_.find(specifier); - if (iter != specifier_guid_map_.end()) { - guid = iter->second; + SpecifierGuidMap::iterator guid_iter = specifier_guid_map_.find(specifier); + if (guid_iter != specifier_guid_map_.end()) { + guid = guid_iter->second; } else { guid = base::GenerateGUID(); specifier_guid_map_[specifier] = guid; @@ -1482,6 +1516,19 @@ network->SetGuid(guid); } +void NetworkStateHandler::UpdateCaptivePortalProvider(NetworkState* network) { + auto portal_iter = + hex_ssid_to_captive_portal_provider_map_.find(network->GetHexSsid()); + if (portal_iter == hex_ssid_to_captive_portal_provider_map_.end()) { + network->SetCaptivePortalProvider("", ""); + return; + } + NET_LOG(EVENT) << "Setting captive portal provider for network: " + << network->guid() << " = " << portal_iter->second.id; + network->SetCaptivePortalProvider(portal_iter->second.id, + portal_iter->second.name); +} + void NetworkStateHandler::EnsureCellularNetwork( ManagedStateList* cellular_networks) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h index f236a4a..eb222f1 100644 --- a/chromeos/network/network_state_handler.h +++ b/chromeos/network/network_state_handler.h
@@ -20,6 +20,7 @@ #include "chromeos/network/managed_state.h" #include "chromeos/network/network_handler.h" #include "chromeos/network/network_handler_callbacks.h" +#include "chromeos/network/network_state.h" #include "chromeos/network/network_type_pattern.h" #include "chromeos/network/shill_property_handler.h" @@ -314,6 +315,12 @@ // Sets the list of devices on which portal check is enabled. void SetCheckPortalList(const std::string& check_portal_list); + // Sets a provider id (e.g. extension id) for a hex encoded SSID. If + // |provider_id| is empty the entry will be erased. + void SetCaptivePortalProviderForHexSsid(const std::string& hex_ssid, + const std::string& provider_id, + const std::string& provider_name); + // Sets the Manager.WakeOnLan property. Note: we do not track this state, we // only set it. void SetWakeOnLanEnabled(bool enabled); @@ -442,6 +449,10 @@ // Ensure a valid GUID for NetworkState. void UpdateGuid(NetworkState* network); + // Look for a matching captive portal provider in + // |hex_ssid_to_captive_portal_provider_map_|. + void UpdateCaptivePortalProvider(NetworkState* network); + // Cellular networks may not have an associated Shill Service (e.g. when the // SIM is locked or a mobile network is not available). To simplify the UI, // if a Cellular Device exists |cellular_networks| will be modified to contain @@ -560,6 +571,11 @@ // NetworkState that is not saved in a profile. SpecifierGuidMap specifier_guid_map_; + // Map of hex SSIDs to captive portal provider info. + // Used to set NetworkState::captive_portal_provider_. + std::map<std::string, NetworkState::CaptivePortalProviderInfo> + hex_ssid_to_captive_portal_provider_map_; + // The state corresponding to the Tether device type. This value is managed by // the Tether component. TechnologyState tether_technology_state_ =
diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc index 6b9fa5a..d9f7256 100644 --- a/chromeos/network/network_state_handler_unittest.cc +++ b/chromeos/network/network_state_handler_unittest.cc
@@ -16,6 +16,7 @@ #include "base/command_line.h" #include "base/macros.h" #include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "base/test/scoped_task_environment.h" #include "base/values.h" #include "chromeos/chromeos_switches.h" @@ -1832,4 +1833,46 @@ EXPECT_EQ("/service/cellular1", cellular_networks[0]->path()); } +TEST_F(NetworkStateHandlerTest, UpdateCaptivePortalProvider) { + constexpr char kProviderId[] = "TestProviderId"; + constexpr char kProviderName[] = "TestProviderName"; + + // Verify initial state. + const NetworkState* wifi1 = network_state_handler_->GetNetworkState( + kShillManagerClientStubDefaultWifi); + ASSERT_TRUE(wifi1); + const NetworkState::CaptivePortalProviderInfo* info = + wifi1->captive_portal_provider(); + EXPECT_EQ(nullptr, info); + + // Verify that setting a captive portal provider applies to existing networks. + std::string hex_ssid = wifi1->GetHexSsid(); + ASSERT_FALSE(hex_ssid.empty()); + network_state_handler_->SetCaptivePortalProviderForHexSsid( + hex_ssid, kProviderId, kProviderName); + base::RunLoop().RunUntilIdle(); + + info = wifi1->captive_portal_provider(); + ASSERT_NE(nullptr, info); + EXPECT_EQ(kProviderId, info->id); + EXPECT_EQ(kProviderName, info->name); + + // Verify that adding a new network sets its captive portal provider. + constexpr char kNewSsid[] = "new_wifi"; + std::string new_hex_ssid = base::HexEncode(kNewSsid, strlen(kNewSsid)); + network_state_handler_->SetCaptivePortalProviderForHexSsid( + new_hex_ssid, kProviderId, kProviderName); + AddService("/service/new_wifi", "new_wifi_guid", kNewSsid, shill::kTypeWifi, + shill::kStateOnline); + base::RunLoop().RunUntilIdle(); + + const NetworkState* new_wifi = + network_state_handler_->GetNetworkState("/service/new_wifi"); + ASSERT_TRUE(new_wifi); + info = new_wifi->captive_portal_provider(); + ASSERT_NE(nullptr, info); + EXPECT_EQ(kProviderId, info->id); + EXPECT_EQ(kProviderName, info->name); +} + } // namespace chromeos
diff --git a/chromeos/network/network_state_unittest.cc b/chromeos/network/network_state_unittest.cc index 6c991e2..05624f6 100644 --- a/chromeos/network/network_state_unittest.cc +++ b/chromeos/network/network_state_unittest.cc
@@ -212,8 +212,9 @@ base::Value("third-party-vpn-provider-extension-id")); EXPECT_TRUE(SetProperty(shill::kProviderProperty, std::move(provider))); SignalInitialPropertiesReceived(); - EXPECT_EQ(network_state_.vpn_provider_type(), shill::kProviderThirdPartyVpn); - EXPECT_EQ(network_state_.vpn_provider_id(), + ASSERT_TRUE(network_state_.vpn_provider()); + EXPECT_EQ(network_state_.vpn_provider()->type, shill::kProviderThirdPartyVpn); + EXPECT_EQ(network_state_.vpn_provider()->id, "third-party-vpn-provider-extension-id"); } @@ -227,8 +228,9 @@ provider->SetKey(shill::kHostProperty, base::Value("package.name.foo")); EXPECT_TRUE(SetProperty(shill::kProviderProperty, std::move(provider))); SignalInitialPropertiesReceived(); - EXPECT_EQ(network_state_.vpn_provider_type(), shill::kProviderArcVpn); - EXPECT_EQ(network_state_.vpn_provider_id(), "package.name.foo"); + ASSERT_TRUE(network_state_.vpn_provider()); + EXPECT_EQ(network_state_.vpn_provider()->type, shill::kProviderArcVpn); + EXPECT_EQ(network_state_.vpn_provider()->id, "package.name.foo"); } TEST_F(NetworkStateTest, Visible) {
diff --git a/components/arc/net/arc_net_host_impl.cc b/components/arc/net/arc_net_host_impl.cc index c7aa02c..aa708cd 100644 --- a/components/arc/net/arc_net_host_impl.cc +++ b/components/arc/net/arc_net_host_impl.cc
@@ -390,7 +390,7 @@ const chromeos::NetworkState* default_network = GetShillBackedNetwork(GetStateHandler()->DefaultNetwork()); if (default_network && default_network->type() == shill::kTypeVPN && - default_network->vpn_provider_type() == shill::kProviderArcVpn) { + default_network->GetVpnProviderType() == shill::kProviderArcVpn) { VLOG(0) << "Disconnecting stale ARC VPN " << default_network->path(); GetNetworkConnectionHandler()->DisconnectNetwork( default_network->path(), base::Bind(&ArcVpnSuccessCallback), @@ -793,7 +793,7 @@ GetShillBackedNetwork(state); if (!shill_backed_network) continue; - if (shill_backed_network->vpn_provider_type() == shill::kProviderArcVpn) { + if (shill_backed_network->GetVpnProviderType() == shill::kProviderArcVpn) { return shill_backed_network->path(); } }
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc index f6478f5b..55b8e61 100644 --- a/components/autofill/content/renderer/autofill_agent.cc +++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -414,18 +414,22 @@ void AutofillAgent::TriggerRefillIfNeeded(const FormData& form) { if (!base::FeatureList::IsEnabled(features::kAutofillDynamicForms)) return; + + ReplaceElementIfNowInvalid(form); + FormFieldData field; FormData updated_form; if (form_util::FindFormAndFieldForFormControlElement(element_, &updated_form, &field) && - !form.DynamicallySameFormAs(updated_form)) { + (!element_.IsAutofilled() || !form.DynamicallySameFormAs(updated_form))) { base::TimeTicks forms_seen_timestamp = base::TimeTicks::Now(); WebLocalFrame* frame = render_frame()->GetWebFrame(); std::vector<FormData> forms; forms.push_back(updated_form); // Always communicate to browser process for topmost frame. - if (!forms.empty() || !frame->Parent()) + if (!forms.empty() || !frame->Parent()) { GetAutofillDriver()->FormsSeen(forms, forms_seen_timestamp); + } } } @@ -1026,11 +1030,62 @@ submitted_forms_.clear(); } +bool AutofillAgent::FindTheUniqueNewVersionOfOldElement( + WebVector<WebFormControlElement>& elements, + bool& element_found, + const WebString& original_element_section, + const WebFormControlElement& original_element) { + for (const WebFormControlElement& current_element : elements) { + if (current_element.IsFocusable() && + original_element.NameForAutofill() == + current_element.NameForAutofill()) { + if (!element_found) { + element_ = current_element; + element_found = true; + } else if (current_element.AutofillSection() == + element_.AutofillSection() || + (current_element.AutofillSection() != + original_element_section && + element_.AutofillSection() != original_element_section)) { + // If there are two elements that share the same name with the element_, + // and the section can't tell them apart, we can't decide between the + // two. + element_ = original_element; + return false; + } else if (current_element.AutofillSection() == + original_element_section) { + // If the current element has the right section, update the element_. + element_ = current_element; + } + } + } + return true; +} + void AutofillAgent::ReplaceElementIfNowInvalid(const FormData& original_form) { // If the document is invalid, bail out. if (element_.GetDocument().IsNull()) return; + WebVector<WebFormElement> forms; + WebVector<WebFormControlElement> elements; + + if (original_form.name.empty()) { + // If the form has no name, check all the forms. + bool element_found = false; + element_.GetDocument().Forms(forms); + for (const WebFormElement& form : forms) { + form.GetFormControlElements(elements); + // If finding a unique element is impossible, return. + if (!FindTheUniqueNewVersionOfOldElement( + elements, element_found, element_.AutofillSection(), element_)) + return; + } + // If the element is not found, we should still check for unowned elements. + if (element_found) + return; + } + if (!element_.Form().IsNull()) { // If |element_|'s parent form has no elements, |element_| is now invalid // and should be updated. @@ -1040,29 +1095,32 @@ return; } - // Try to find the new version of the form. WebFormElement form_element; - WebVector<WebFormElement> forms; - element_.GetDocument().Forms(forms); - for (const WebFormElement& form : forms) { - if (original_form.name == form.GetName().Utf16() || - original_form.name == form.GetAttribute("id").Utf16()) { - form_element = form; - break; + if (!original_form.name.empty()) { + // Try to find the new version of the form. + element_.GetDocument().Forms(forms); + for (const WebFormElement& form : forms) { + if (original_form.name == form.GetName().Utf16() || + original_form.name == form.GetAttribute("id").Utf16()) { + form_element = form; + break; + } } } - WebVector<WebFormControlElement> elements; if (form_element.IsNull()) { // Could not find the new version of the form, get all the unowned elements. std::vector<WebElement> fieldsets; elements = form_util::GetUnownedAutofillableFormFieldElements( element_.GetDocument().All(), &fieldsets); - } else { - // Get all the elements of the new version of the form. - form_element.GetFormControlElements(elements); + bool element_found = false; + FindTheUniqueNewVersionOfOldElement(elements, element_found, + element_.AutofillSection(), element_); + return; } - + // This is the case for owned fields that belong to the right named form. + // Get all the elements of the new version of the form. + form_element.GetFormControlElements(elements); // Try to find the new version of the last interacted element. for (const WebFormControlElement& element : elements) { if (element_.NameForAutofill() == element.NameForAutofill()) {
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h index ba36f73a..4977eace 100644 --- a/components/autofill/content/renderer/autofill_agent.h +++ b/components/autofill/content/renderer/autofill_agent.h
@@ -29,6 +29,10 @@ namespace blink { class WebNode; class WebView; +class WebString; +class WebFormControlElement; +template <typename T> +class WebVector; } namespace autofill { @@ -266,6 +270,15 @@ // cleared in this method. void OnFormNoLongerSubmittable(); + // For no name forms, and unowned elements, try to see if there is a unique + // element in the updated form that corresponds to the old |element_|. + // Returns false if more than one element matches the |element_|. + bool FindTheUniqueNewVersionOfOldElement( + blink::WebVector<blink::WebFormControlElement>& elements, + bool& element_found, + const blink::WebString& original_element_section, + const blink::WebFormControlElement& original_element); + // Check whether |element_| was removed or replaced dynamically on the page. // If so, looks for the same element in the updated |form| and replaces the // |element_| with it if it's found.
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index 16621e5..1c4a4555 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -181,6 +181,8 @@ "webdata/autofill_table_encryptor.h", "webdata/autofill_table_encryptor_factory.cc", "webdata/autofill_table_encryptor_factory.h", + "webdata/autofill_wallet_metadata_sync_bridge.cc", + "webdata/autofill_wallet_metadata_sync_bridge.h", "webdata/autofill_wallet_metadata_syncable_service.cc", "webdata/autofill_wallet_metadata_syncable_service.h", "webdata/autofill_wallet_sync_bridge.cc",
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index f423f18..906ef7e 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc
@@ -1965,7 +1965,12 @@ DCHECK(itr != filling_contexts_map_.end()); FillingContext* filling_context = itr->second.get(); - DCHECK(!filling_context->attempted_refill); + // The refill attempt can happen from different paths, some of which happen + // after waiting for a while. Therefore, although this condition has been + // checked prior to calling TriggerRefill, it may not hold, when we get here. + if (filling_context->attempted_refill) + return; + filling_context->attempted_refill = true; // Try to find the field from which the original field originated.
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc new file mode 100644 index 0000000..f836172c --- /dev/null +++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.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 "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h" + +#include <utility> + +#include "base/logging.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/sync/model_impl/client_tag_based_model_type_processor.h" + +namespace autofill { + +namespace { + +// Address to this variable used as the user data key. +static int kAutofillWalletMetadataSyncBridgeUserDataKey = 0; + +} // namespace + +// static +void AutofillWalletMetadataSyncBridge::CreateForWebDataServiceAndBackend( + const std::string& app_locale, + AutofillWebDataBackend* web_data_backend, + AutofillWebDataService* web_data_service) { + web_data_service->GetDBUserData()->SetUserData( + &kAutofillWalletMetadataSyncBridgeUserDataKey, + std::make_unique<AutofillWalletMetadataSyncBridge>( + std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( + syncer::AUTOFILL_WALLET_DATA, + /*dump_stack=*/base::RepeatingClosure()))); +} + +// static +syncer::ModelTypeSyncBridge* +AutofillWalletMetadataSyncBridge::FromWebDataService( + AutofillWebDataService* web_data_service) { + return static_cast<AutofillWalletMetadataSyncBridge*>( + web_data_service->GetDBUserData()->GetUserData( + &kAutofillWalletMetadataSyncBridgeUserDataKey)); +} + +AutofillWalletMetadataSyncBridge::AutofillWalletMetadataSyncBridge( + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor) + : ModelTypeSyncBridge(std::move(change_processor)) {} + +AutofillWalletMetadataSyncBridge::~AutofillWalletMetadataSyncBridge() {} + +std::unique_ptr<syncer::MetadataChangeList> +AutofillWalletMetadataSyncBridge::CreateMetadataChangeList() { + NOTIMPLEMENTED(); + return nullptr; +} + +base::Optional<syncer::ModelError> +AutofillWalletMetadataSyncBridge::MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) { + NOTIMPLEMENTED(); + return base::nullopt; +} + +base::Optional<syncer::ModelError> +AutofillWalletMetadataSyncBridge::ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) { + NOTIMPLEMENTED(); + return base::nullopt; +} + +void AutofillWalletMetadataSyncBridge::GetData(StorageKeyList storage_keys, + DataCallback callback) { + NOTIMPLEMENTED(); +} + +void AutofillWalletMetadataSyncBridge::GetAllDataForDebugging( + DataCallback callback) { + NOTIMPLEMENTED(); +} + +std::string AutofillWalletMetadataSyncBridge::GetClientTag( + const syncer::EntityData& entity_data) { + NOTIMPLEMENTED(); + return ""; +} + +std::string AutofillWalletMetadataSyncBridge::GetStorageKey( + const syncer::EntityData& entity_data) { + NOTIMPLEMENTED(); + return ""; +} + +} // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h new file mode 100644 index 0000000..ed20fba --- /dev/null +++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
@@ -0,0 +1,63 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNC_BRIDGE_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNC_BRIDGE_H_ + +#include <memory> +#include <string> + +#include "base/macros.h" +#include "base/supports_user_data.h" +#include "components/sync/model/metadata_change_list.h" +#include "components/sync/model/model_error.h" +#include "components/sync/model/model_type_change_processor.h" +#include "components/sync/model/model_type_sync_bridge.h" + +namespace autofill { + +class AutofillWebDataBackend; +class AutofillWebDataService; + +// Sync bridge responsible for propagating local changes to the processor and +// applying remote changes to the local database. +class AutofillWalletMetadataSyncBridge : public base::SupportsUserData::Data, + public syncer::ModelTypeSyncBridge { + public: + // Factory method that hides dealing with change_processor and also stores the + // created bridge within |web_data_service|. This method should only be + // called on |web_data_service|'s DB thread. + static void CreateForWebDataServiceAndBackend( + const std::string& app_locale, + AutofillWebDataBackend* webdata_backend, + AutofillWebDataService* web_data_service); + + static syncer::ModelTypeSyncBridge* FromWebDataService( + AutofillWebDataService* web_data_service); + + explicit AutofillWalletMetadataSyncBridge( + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor); + ~AutofillWalletMetadataSyncBridge() override; + + // ModelTypeSyncBridge implementation. + std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList() + override; + base::Optional<syncer::ModelError> MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) override; + base::Optional<syncer::ModelError> ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_changes) override; + void GetData(StorageKeyList storage_keys, DataCallback callback) override; + void GetAllDataForDebugging(DataCallback callback) override; + std::string GetClientTag(const syncer::EntityData& entity_data) override; + std::string GetStorageKey(const syncer::EntityData& entity_data) override; + + private: + DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncBridge); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNC_BRIDGE_H_
diff --git a/components/autofill_assistant/OWNERS b/components/autofill_assistant/OWNERS new file mode 100644 index 0000000..483685a --- /dev/null +++ b/components/autofill_assistant/OWNERS
@@ -0,0 +1 @@ +gogerald@chromium.org \ No newline at end of file
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn new file mode 100644 index 0000000..40ac937 --- /dev/null +++ b/components/autofill_assistant/browser/BUILD.gn
@@ -0,0 +1,35 @@ +# 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("//third_party/protobuf/proto_library.gni") + +proto_library("proto") { + sources = [ + "assistant.proto", + ] +} + +static_library("browser") { + sources = [ + "assistant_controller.cc", + "assistant_controller.h", + "assistant_protocol_utils.cc", + "assistant_protocol_utils.h", + "assistant_script.h", + "assistant_script_executor.cc", + "assistant_script_executor.h", + "assistant_script_executor_delegate.h", + "assistant_service.cc", + "assistant_service.h", + ] + + public_deps = [ + ":proto", + "//base", + "//components/version_info", + "//content/public/browser", + "//google_apis", + "//net", + ] +}
diff --git a/components/autofill_assistant/browser/DEPS b/components/autofill_assistant/browser/DEPS new file mode 100644 index 0000000..66a201ce --- /dev/null +++ b/components/autofill_assistant/browser/DEPS
@@ -0,0 +1,7 @@ +include_rules = [ + "+components/version_info/version_info.h", + "+content/public/browser", + "+google_apis", + "+net", + "+services/network/public/cpp", +] \ No newline at end of file
diff --git a/components/autofill_assistant/browser/assistant.proto b/components/autofill_assistant/browser/assistant.proto new file mode 100644 index 0000000..71cac77 --- /dev/null +++ b/components/autofill_assistant/browser/assistant.proto
@@ -0,0 +1,55 @@ +// 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. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package autofill_assistant; + +// Context contains client environment details. It's used to filter the +// scripts that can be surfaced to the user. +message ClientContextProto { + required string chrome_version = 1; +} + +// Get the list of scripts that can potentially be run on a url. +message SupportsScriptRequestProto { + required string url = 1; + required ClientContextProto client_context = 2; +} + +// Response of the list of supported scripts. +message SupportsScriptResponseProto { + repeated SupportedScriptProto scripts = 1; +} + +// Supported script. +message SupportedScriptProto { + // This is the internal name of the script. + required string path = 1; + + message PresentationProto { + // Name to use when suggesting this script to users. + optional string name = 1; + } + optional PresentationProto presentation = 2; +} + +enum PolicyType { + UNKNOWN_POLICY = 0; + SCRIPT = 1; + PAGE = 2; + VALIDATION = 3; + TRACE = 4; +} + +// Initial request to get a script's actions. +message InitialScriptActionRequestProto { + message QueryProto { + required string script_path = 1; + optional PolicyType policy = 2; + } + required QueryProto query = 1; +}
diff --git a/components/autofill_assistant/browser/assistant_controller.cc b/components/autofill_assistant/browser/assistant_controller.cc new file mode 100644 index 0000000..0398628 --- /dev/null +++ b/components/autofill_assistant/browser/assistant_controller.cc
@@ -0,0 +1,56 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/assistant_controller.h" + +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" + +namespace autofill_assistant { +// static +void AssistantController::CreateAndStartForWebContents( + content::WebContents* web_contents) { + new AssistantController(web_contents); +} + +AssistantService* AssistantController::GetAssistantService() { + return assistant_service_.get(); +} + +AssistantController::AssistantController(content::WebContents* web_contents) + : content::WebContentsObserver(web_contents), + assistant_service_(std::make_unique<AssistantService>( + web_contents->GetBrowserContext())) { + if (!web_contents->IsLoading()) { + GetAssistantScripts(); + } +} + +AssistantController::~AssistantController() {} + +void AssistantController::OnGetAssistantScripts( + AssistantService::AssistantScripts scripts) { + assistant_scripts_ = std::move(scripts); +} + +void AssistantController::DidFinishLoad( + content::RenderFrameHost* render_frame_host, + const GURL& validated_url) { + // TODO(crbug.com/806868): Find a better time to get and update assistant + // scripts. + GetAssistantScripts(); +} + +void AssistantController::WebContentsDestroyed() { + delete this; +} + +void AssistantController::GetAssistantScripts() { + assistant_service_->GetAssistantScriptsForUrl( + web_contents()->GetLastCommittedURL(), + base::BindOnce(&AssistantController::OnGetAssistantScripts, + base::Unretained(this))); +} + +} // namespace autofill_assistant \ No newline at end of file
diff --git a/components/autofill_assistant/browser/assistant_controller.h b/components/autofill_assistant/browser/assistant_controller.h new file mode 100644 index 0000000..fa91345 --- /dev/null +++ b/components/autofill_assistant/browser/assistant_controller.h
@@ -0,0 +1,49 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_CONTROLLER_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_CONTROLLER_H_ + +#include "components/autofill_assistant/browser/assistant_script_executor_delegate.h" +#include "components/autofill_assistant/browser/assistant_service.h" +#include "content/public/browser/web_contents_observer.h" + +namespace content { +class RenderFrameHost; +class WebContents; +} // namespace content + +namespace autofill_assistant { +// Autofill assistant controller controls autofill assistant action detection, +// display, execution and so on. The instance of this object self deletes when +// the web contents is being destroyed. +class AssistantController : public AssistantScriptExecutorDelegate, + private content::WebContentsObserver { + public: + static void CreateAndStartForWebContents(content::WebContents* web_contents); + + // Overrides AssistantScriptExecutorDelegate: + AssistantService* GetAssistantService() override; + + private: + explicit AssistantController(content::WebContents* web_contents); + ~AssistantController() override; + + void GetAssistantScripts(); + void OnGetAssistantScripts(AssistantService::AssistantScripts scripts); + + // Overrides content::WebContentsObserver: + void DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url) override; + void WebContentsDestroyed() override; + + std::unique_ptr<AssistantService> assistant_service_; + AssistantService::AssistantScripts assistant_scripts_; + + DISALLOW_COPY_AND_ASSIGN(AssistantController); +}; + +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_CONTROLLER_H_ \ No newline at end of file
diff --git a/components/autofill_assistant/browser/assistant_protocol_utils.cc b/components/autofill_assistant/browser/assistant_protocol_utils.cc new file mode 100644 index 0000000..4b777c3 --- /dev/null +++ b/components/autofill_assistant/browser/assistant_protocol_utils.cc
@@ -0,0 +1,74 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/assistant_protocol_utils.h" + +#include "base/logging.h" +#include "components/autofill_assistant/browser/assistant.pb.h" +#include "components/version_info/version_info.h" +#include "url/gurl.h" + +namespace autofill_assistant { + +// static +std::string AssistantProtocolUtils::CreateGetScriptsRequest(const GURL& url) { + DCHECK(!url.is_empty()); + ClientContextProto context_proto; + context_proto.set_chrome_version( + version_info::GetProductNameAndVersionForUserAgent()); + + SupportsScriptRequestProto script_proto; + script_proto.set_url(url.spec()); + script_proto.set_allocated_client_context(&context_proto); + + std::string serialized_script_proto; + bool success = script_proto.SerializeToString(&serialized_script_proto); + DCHECK(success); + return serialized_script_proto; +} + +// static +AssistantProtocolUtils::AssistantScripts +AssistantProtocolUtils::ParseAssistantScripts(const std::string& response) { + DCHECK(!response.empty()); + AssistantScripts scripts; + + SupportsScriptResponseProto response_proto; + if (!response_proto.ParseFromString(response)) { + LOG(ERROR) << "Failed to parse getting assistant scripts response."; + return scripts; + } + + for (const auto& script : response_proto.scripts()) { + std::string name = ""; + if (script.has_presentation() && script.presentation().has_name()) { + name = script.presentation().name(); + } + auto assistant_script = std::make_unique<AssistantScript>(); + assistant_script->name = name; + assistant_script->path = script.path(); + scripts[assistant_script.get()] = std::move(assistant_script); + } + + return scripts; +} + +// static +std::string AssistantProtocolUtils::CreateInitialScriptActionRequest( + const std::string& script_path) { + InitialScriptActionRequestProto::QueryProto query; + query.set_script_path(script_path); + query.set_policy(PolicyType::SCRIPT); + + InitialScriptActionRequestProto initial_request_proto; + initial_request_proto.set_allocated_query(&query); + + std::string serialized_initial_request_proto; + bool success = initial_request_proto.SerializeToString( + &serialized_initial_request_proto); + DCHECK(success); + return serialized_initial_request_proto; +} + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/assistant_protocol_utils.h b/components/autofill_assistant/browser/assistant_protocol_utils.h new file mode 100644 index 0000000..391ab89 --- /dev/null +++ b/components/autofill_assistant/browser/assistant_protocol_utils.h
@@ -0,0 +1,40 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_PROTOCOL_UTILS_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_PROTOCOL_UTILS_H_ + +#include "components/autofill_assistant/browser/assistant_script.h" + +#include <map> +#include <string> + +class GURL; + +namespace autofill_assistant { +// Autofill assistant protocol related convenient utils. +class AssistantProtocolUtils { + public: + // Create getting autofill assistant scripts request for the given + // |url|. + static std::string CreateGetScriptsRequest(const GURL& url); + + using AssistantScripts = + std::map<AssistantScript*, std::unique_ptr<AssistantScript>>; + // Parse assistant scripts from the given |response|, which should not be an + // empty string. + static AssistantScripts ParseAssistantScripts(const std::string& response); + + // Create initial request to get script actions for the given |script_path|. + static std::string CreateInitialScriptActionRequest( + const std::string& script_path); + + private: + // To avoid instantiate this class by accident. + AssistantProtocolUtils() = delete; + ~AssistantProtocolUtils() = delete; +}; +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_PROTOCOL_UTILS_H_ \ No newline at end of file
diff --git a/components/autofill_assistant/browser/assistant_script.h b/components/autofill_assistant/browser/assistant_script.h new file mode 100644 index 0000000..8bee4ba --- /dev/null +++ b/components/autofill_assistant/browser/assistant_script.h
@@ -0,0 +1,20 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_H_ + +#include <string> + +namespace autofill_assistant { + +// Assistant script represents a sequence of client actions. +struct AssistantScript { + std::string name; + std::string path; +}; + +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_H_ \ No newline at end of file
diff --git a/components/autofill_assistant/browser/assistant_script_executor.cc b/components/autofill_assistant/browser/assistant_script_executor.cc new file mode 100644 index 0000000..b4a57ce --- /dev/null +++ b/components/autofill_assistant/browser/assistant_script_executor.cc
@@ -0,0 +1,34 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/assistant_script_executor.h" + +#include "base/bind.h" +#include "components/autofill_assistant/browser/assistant_service.h" + +namespace autofill_assistant { +AssistantScriptExecutor::AssistantScriptExecutor( + AssistantScript* script, + AssistantScriptExecutorDelegate* delegate) + : script_(script), delegate_(delegate), weak_ptr_factory_(this) { + DCHECK(script_); + DCHECK(delegate_); +} +AssistantScriptExecutor::~AssistantScriptExecutor() {} + +void AssistantScriptExecutor::Run(RunScriptCallback callback) { + callback_ = std::move(callback); + DCHECK(delegate_->GetAssistantService()); + + delegate_->GetAssistantService()->GetAssistantActions( + script_->path, + base::BindOnce(&AssistantScriptExecutor::onGetAssistantActions, + weak_ptr_factory_.GetWeakPtr())); +} + +void AssistantScriptExecutor::onGetAssistantActions(bool result) { + NOTIMPLEMENTED(); +} + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/assistant_script_executor.h b/components/autofill_assistant/browser/assistant_script_executor.h new file mode 100644 index 0000000..104545b0 --- /dev/null +++ b/components/autofill_assistant/browser/assistant_script_executor.h
@@ -0,0 +1,39 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_H_ + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "components/autofill_assistant/browser/assistant_script.h" +#include "components/autofill_assistant/browser/assistant_script_executor_delegate.h" + +namespace autofill_assistant { +// Class to execute an assistant script. +class AssistantScriptExecutor { + public: + // |script| and |delegate| should outlive this object and should not be + // nullptr. + AssistantScriptExecutor(AssistantScript* script, + AssistantScriptExecutorDelegate* delegate); + ~AssistantScriptExecutor(); + + using RunScriptCallback = base::OnceCallback<void(bool)>; + void Run(RunScriptCallback callback); + + private: + void onGetAssistantActions(bool result); + + AssistantScript* script_; + AssistantScriptExecutorDelegate* delegate_; + + RunScriptCallback callback_; + + base::WeakPtrFactory<AssistantScriptExecutor> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(AssistantScriptExecutor); +}; +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_H_
diff --git a/components/autofill_assistant/browser/assistant_script_executor_delegate.h b/components/autofill_assistant/browser/assistant_script_executor_delegate.h new file mode 100644 index 0000000..49d1b69 --- /dev/null +++ b/components/autofill_assistant/browser/assistant_script_executor_delegate.h
@@ -0,0 +1,21 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_DELEGATE_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_DELEGATE_H_ + +namespace autofill_assistant { + +class AssistantService; + +class AssistantScriptExecutorDelegate { + public: + virtual AssistantService* GetAssistantService() = 0; + + protected: + virtual ~AssistantScriptExecutorDelegate() {} +}; +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SCRIPT_EXECUTOR_DELEGATE_H_
diff --git a/components/autofill_assistant/browser/assistant_service.cc b/components/autofill_assistant/browser/assistant_service.cc new file mode 100644 index 0000000..8e65f21 --- /dev/null +++ b/components/autofill_assistant/browser/assistant_service.cc
@@ -0,0 +1,166 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/assistant_service.h" + +#include "base/strings/strcat.h" +#include "components/autofill_assistant/browser/assistant_protocol_utils.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/storage_partition.h" +#include "google_apis/google_api_keys.h" +#include "net/base/load_flags.h" +#include "net/http/http_status_code.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "url/url_canon_stdstring.h" + +namespace { +// TODO(crbug.com/806868): Provide correct server and endpoint. +const char* const kAutofillAssistantServer = ""; +const char* const kScriptEndpoint = ""; +const char* const kActionEndpoint = ""; + +net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("autofill_assistant_service", R"( + semantics { + sender: "Autofill Assistant" + description: + "Chromium posts requests to autofill assistant server to get + assistant scripts for a URL." + trigger: + "A user opens a URL that could be assisted by autofill + assistant server." + data: "None." + destination: GOOGLE_OWNED_SERVICE + } + policy { + cookies_allowed: NO + setting: + "This feature can be disabled in settings." + policy_exception_justification: "Not implemented." + })"); +} // namespace + +namespace autofill_assistant { + +AssistantService::AssistantService(content::BrowserContext* context) + : context_(context) { + std::string api_key = google_apis::GetAPIKey(); + + url::StringPieceReplacements<std::string> script_replacements; + script_replacements.SetPathStr(kScriptEndpoint); + script_replacements.SetQueryStr(api_key); + assistant_script_server_url_ = + GURL(kAutofillAssistantServer).ReplaceComponents(script_replacements); + + url::StringPieceReplacements<std::string> action_replacements; + action_replacements.SetPathStr(kActionEndpoint); + action_replacements.SetQueryStr(api_key); + assistant_script_action_server_url_ = + GURL(kAutofillAssistantServer).ReplaceComponents(action_replacements); +} + +AssistantService::~AssistantService() {} + +void AssistantService::GetAssistantScriptsForUrl( + const GURL& url, + GetAssistantScriptsForUrlCallback callback) { + DCHECK(url.is_valid()); + + std::unique_ptr<AssistantLoader> assistant_loader = + std::make_unique<AssistantLoader>(); + assistant_loader->scripts_callback = std::move(callback); + assistant_loader->loader = + CreateAndStartLoader(assistant_script_server_url_, + AssistantProtocolUtils::CreateGetScriptsRequest(url), + assistant_loader.get()); + assistant_loaders_[assistant_loader.get()] = std::move(assistant_loader); +} + +void AssistantService::GetAssistantActions( + const std::string& script_path, + GetAssistantActionsCallback callback) { + DCHECK(!script_path.empty()); + + std::unique_ptr<AssistantLoader> assistant_loader = + std::make_unique<AssistantLoader>(); + assistant_loader->actions_callback = std::move(callback); + assistant_loader->loader = CreateAndStartLoader( + assistant_script_action_server_url_, + AssistantProtocolUtils::CreateInitialScriptActionRequest(script_path), + assistant_loader.get()); + assistant_loaders_[assistant_loader.get()] = std::move(assistant_loader); +} + +AssistantService::AssistantLoader::AssistantLoader() {} +AssistantService::AssistantLoader::~AssistantLoader() {} + +std::unique_ptr<network::SimpleURLLoader> +AssistantService::CreateAndStartLoader(const GURL& server_url, + const std::string& request, + AssistantLoader* loader) { + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->url = server_url; + resource_request->method = "POST"; + resource_request->fetch_redirect_mode = + network::mojom::FetchRedirectMode::kError; + resource_request->load_flags = + net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES; + std::unique_ptr<network::SimpleURLLoader> simple_loader = + network::SimpleURLLoader::Create(std::move(resource_request), + traffic_annotation); + simple_loader->AttachStringForUpload(request, "application/x-protobuffer"); + simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + content::BrowserContext::GetDefaultStoragePartition(context_) + ->GetURLLoaderFactoryForBrowserProcess() + .get(), + base::BindOnce(&AssistantService::OnURLLoaderComplete, + base::Unretained(this), loader)); + return simple_loader; +} + +void AssistantService::OnURLLoaderComplete( + AssistantLoader* loader, + std::unique_ptr<std::string> response_body) { + auto loader_it = assistant_loaders_.find(loader); + DCHECK(loader_it != assistant_loaders_.end()); + std::unique_ptr<AssistantLoader> assistant_loader = + std::move(loader_it->second); + assistant_loaders_.erase(loader_it); + DCHECK(assistant_loader); + + int response_code = 0; + if (assistant_loader->loader->ResponseInfo() && + assistant_loader->loader->ResponseInfo()->headers) { + response_code = + assistant_loader->loader->ResponseInfo()->headers->response_code(); + } + if (assistant_loader->loader->NetError() != net::OK || response_code != 200) { + LOG(ERROR) << "Communicating with autofill assistant server error NetError=" + << assistant_loader->loader->NetError() + << " response_code=" << response_code; + + DCHECK(assistant_loader->scripts_callback || + assistant_loader->actions_callback); + if (assistant_loader->scripts_callback) + std::move(assistant_loader->scripts_callback).Run(AssistantScripts()); + else if (assistant_loader->actions_callback) + std::move(assistant_loader->actions_callback).Run(false); + return; + } + + std::string response_body_str; + if (response_body) + response_body_str = std::move(*response_body); + DCHECK(assistant_loader->scripts_callback || + assistant_loader->actions_callback); + if (assistant_loader->scripts_callback) { + std::move(assistant_loader->scripts_callback) + .Run(AssistantProtocolUtils::ParseAssistantScripts(response_body_str)); + } else if (assistant_loader->actions_callback) { + // TODO(crbug.com/806868): Parse assistant actions. + std::move(assistant_loader->actions_callback).Run(false); + } +} + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/assistant_service.h b/components/autofill_assistant/browser/assistant_service.h new file mode 100644 index 0000000..637cbb6 --- /dev/null +++ b/components/autofill_assistant/browser/assistant_service.h
@@ -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. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SERVICE_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SERVICE_H_ + +#include <map> +#include <memory> + +#include "base/callback.h" +#include "components/autofill_assistant/browser/assistant_script.h" +#include "services/network/public/cpp/simple_url_loader.h" +#include "url/gurl.h" + +namespace content { +class BrowserContext; +} + +namespace autofill_assistant { +// Autofill assistant service to communicate with the server to get scripts and +// client actions. +class AssistantService { + public: + AssistantService(content::BrowserContext* context); + ~AssistantService(); + + // Get assistant scripts for a given |url|, which should be a valid URL. + using AssistantScripts = + std::map<AssistantScript*, std::unique_ptr<AssistantScript>>; + using GetAssistantScriptsForUrlCallback = + base::OnceCallback<void(AssistantScripts)>; + void GetAssistantScriptsForUrl(const GURL& url, + GetAssistantScriptsForUrlCallback callback); + + // Get assistant actions. + using GetAssistantActionsCallback = base::OnceCallback<void(bool)>; + void GetAssistantActions(const std::string& script_path, + GetAssistantActionsCallback callback); + + private: + // Struct to store assistant scripts and actions request. + struct AssistantLoader { + AssistantLoader(); + ~AssistantLoader(); + + // One of the |scripts_callback| and |actions_callback| must be nullptr; + GetAssistantScriptsForUrlCallback scripts_callback; + GetAssistantActionsCallback actions_callback; + std::unique_ptr<network::SimpleURLLoader> loader; + }; + std::unique_ptr<network::SimpleURLLoader> CreateAndStartLoader( + const GURL& server_url, + const std::string& request, + AssistantLoader* loader); + void OnURLLoaderComplete(AssistantLoader* loader, + std::unique_ptr<std::string> response_body); + + content::BrowserContext* context_; + GURL assistant_script_server_url_; + GURL assistant_script_action_server_url_; + + // Destroying this object will cancel ongoing requests. + std::map<AssistantLoader*, std::unique_ptr<AssistantLoader>> + assistant_loaders_; + + DISALLOW_COPY_AND_ASSIGN(AssistantService); +}; + +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ASSISTANT_SERVICE_H_
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc index 713f268..3f87705 100644 --- a/components/browser_sync/profile_sync_components_factory_impl.cc +++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -14,6 +14,7 @@ #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h" #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h" +#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/browser/webdata/web_data_model_type_controller.h" @@ -69,7 +70,7 @@ // TODO(jkrcal): Deal with the (probably rare) race condition when we call // bridges' FromWebDataService() before calling // CreateForWebDataServiceAndBackend() in WebDataServiceWrapper. This TODO - // also applies to the second function below and to analogous code in + // also applies to all analogous functions below and to analogous code in // SyncClient::GetControllerDelegateForModelType(). return autofill::AutocompleteSyncBridge::FromWebDataService(service) ->change_processor() @@ -84,6 +85,22 @@ ->GetControllerDelegateOnUIThread(); } +base::WeakPtr<syncer::ModelTypeControllerDelegate> +AutofillWalletDelegateFromDataService( + autofill::AutofillWebDataService* service) { + return autofill::AutofillWalletSyncBridge::FromWebDataService(service) + ->change_processor() + ->GetControllerDelegateOnUIThread(); +} + +base::WeakPtr<syncer::ModelTypeControllerDelegate> +AutofillWalletMetadataDelegateFromDataService( + autofill::AutofillWebDataService* service) { + return autofill::AutofillWalletMetadataSyncBridge::FromWebDataService(service) + ->change_processor() + ->GetControllerDelegateOnUIThread(); +} + } // namespace ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl( @@ -157,7 +174,7 @@ std::make_unique<autofill::WebDataModelTypeController>( syncer::AUTOFILL_WALLET_DATA, sync_client_, db_thread_, web_data_service_, - base::BindRepeating(&AutofillProfileDelegateFromDataService))); + base::BindRepeating(&AutofillWalletDelegateFromDataService))); } else { controllers.push_back( std::make_unique<AutofillWalletDataTypeController>( @@ -170,9 +187,20 @@ // is syncing and metadata sync is not explicitly disabled. if (!wallet_disabled && !disabled_types.Has(syncer::AUTOFILL_WALLET_METADATA)) { - controllers.push_back(std::make_unique<AutofillWalletDataTypeController>( - syncer::AUTOFILL_WALLET_METADATA, db_thread_, error_callback, - sync_client_, web_data_service_)); + if (base::FeatureList::IsEnabled( + switches::kSyncUSSAutofillWalletMetadata)) { + controllers.push_back( + std::make_unique<autofill::WebDataModelTypeController>( + syncer::AUTOFILL_WALLET_METADATA, sync_client_, db_thread_, + web_data_service_, + base::BindRepeating( + &AutofillWalletMetadataDelegateFromDataService))); + } else { + controllers.push_back( + std::make_unique<AutofillWalletDataTypeController>( + syncer::AUTOFILL_WALLET_METADATA, db_thread_, error_callback, + sync_client_, web_data_service_)); + } } }
diff --git a/components/crash/android/BUILD.gn b/components/crash/android/BUILD.gn index 425e96dc..97b8d2b4 100644 --- a/components/crash/android/BUILD.gn +++ b/components/crash/android/BUILD.gn
@@ -5,7 +5,8 @@ import("//build/config/android/rules.gni") _jni_sources = - [ "java/src/org/chromium/components/crash/browser/CrashDumpManager.java" ] + [ "java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java", + "java/src/org/chromium/components/crash/browser/CrashDumpManager.java" ] generate_jni("jni_headers") { sources = _jni_sources
diff --git a/components/crash/android/java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java b/components/crash/android/java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java new file mode 100644 index 0000000..a9f6a23 --- /dev/null +++ b/components/crash/android/java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java
@@ -0,0 +1,59 @@ +// 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.components.crash.browser; + +import org.chromium.base.Log; +import org.chromium.base.ThreadUtils; +import org.chromium.base.annotations.CalledByNative; + +/** + * A Java-side bridge for notifying an observer when a child process has crashed. + * + * Crashpad writes a minidump for a child process in the time between the child receives a crash + * signal and when it exits. After the child process exits, Crashpad should have completed writing + * a minidump to its CrashReportDatabase and this class's childCrashed() is called, executing any + * registered callback. + * + * It is expected that the callback will be used to handle the newly created dump by, e.g. attaching + * a logcat and scheduling it for upload. + */ +public class ChildProcessCrashObserver { + private static final String TAG = "ChildCrashObserver"; + + /** + * An interface for registering a callback to be executed when a child process crashes. + */ + public interface ChildCrashedCallback { public void childCrashed(int pid); } + + /** + * The globally registered callback for responding to child process crashes, or null if no + * callback has been registered yet. + */ + private static ChildCrashedCallback sCallback; + + /** + * Registers a callback for responding to child process crashes. May be called at most once, and + * only on the UI thread. + * + * @param callback The callback to trigger when a child process has exited due to a crash. + */ + public static void registerCrashCallback(ChildCrashedCallback callback) { + ThreadUtils.assertOnUiThread(); + assert sCallback == null; + sCallback = callback; + } + + /** + * Notifies any registered observer that a child process has exited due to an apparent crash. + */ + @CalledByNative + public static void childCrashed(int pid) { + if (sCallback == null) { + Log.w(TAG, "Ignoring crash observed before a callback was registered..."); + return; + } + sCallback.childCrashed(pid); + } +}
diff --git a/components/crash/content/browser/crash_dump_manager_android_unittest.cc b/components/crash/content/browser/crash_dump_manager_android_unittest.cc index 83fd396..d378372 100644 --- a/components/crash/content/browser/crash_dump_manager_android_unittest.cc +++ b/components/crash/content/browser/crash_dump_manager_android_unittest.cc
@@ -129,34 +129,6 @@ base::Unretained(test_harness_))); } -TEST_F(CrashDumpManagerTest, NoDumpCreated) { - base::HistogramTester histogram_tester; - CrashDumpManager* manager = CrashDumpManager::GetInstance(); - - CrashMetricsReporterObserver observer; - crash_reporter::CrashMetricsReporter::GetInstance()->AddObserver(&observer); - - crash_reporter::ChildExitObserver::TerminationInfo termination_info; - termination_info.process_host_id = 1; - termination_info.pid = base::kNullProcessHandle; - termination_info.process_type = content::PROCESS_TYPE_RENDERER; - termination_info.app_state = - base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES; - termination_info.normal_termination = false; - termination_info.binding_state = base::android::ChildBindingState::STRONG; - termination_info.was_killed_intentionally_by_browser = false; - termination_info.was_oom_protected_status = true; - base::PostTaskWithTraits( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, - base::BindOnce(&CrashDumpManager::ProcessMinidumpFileFromChild, - base::Unretained(manager), base::FilePath(), - termination_info)); - observer.WaitForProcessed(); - - histogram_tester.ExpectTotalCount("Tab.RendererDetailedExitStatus", 0); - EXPECT_EQ(0, dumps_uploaded_); -} - TEST_F(CrashDumpManagerTest, NonOomCrash) { base::HistogramTester histogram_tester;
diff --git a/components/crash/content/browser/crash_metrics_reporter_android.cc b/components/crash/content/browser/crash_metrics_reporter_android.cc index 3c2babb..8b8e741 100644 --- a/components/crash/content/browser/crash_metrics_reporter_android.cc +++ b/components/crash/content/browser/crash_metrics_reporter_android.cc
@@ -112,10 +112,9 @@ const ChildExitObserver::TerminationInfo& info, breakpad::CrashDumpManager::CrashDumpStatus status) { ReportedCrashTypeSet reported_counts; - if (status == breakpad::CrashDumpManager::CrashDumpStatus::kMissingDump) { - NotifyObservers(info.process_host_id, reported_counts); + // Avoid duplicating processing for the same process. + if (status == breakpad::CrashDumpManager::CrashDumpStatus::kMissingDump) return; - } bool has_valid_dump = false; switch (status) {
diff --git a/components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java b/components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java index 9e1f79f..d624417 100644 --- a/components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java +++ b/components/cronet/android/java/src/org/chromium/net/urlconnection/MessageLoop.java
@@ -27,6 +27,12 @@ // this might cause the loop to terminate immediately if there is a quit // task enqueued. private boolean mLoopFailed = false; + // The exception that caused mLoopFailed to be set to true. Will be + // rethrown if loop() is called again. If mLoopFailed is set then + // exactly one of mPriorInterruptedIOException and mPriorRuntimeException + // will be set. + private InterruptedIOException mPriorInterruptedIOException; + private RuntimeException mPriorRuntimeException; // Used when assertions are enabled to enforce single-threaded use. private static final long INVALID_THREAD_ID = -1; @@ -96,8 +102,11 @@ long startNano = System.nanoTime(); long timeoutNano = TimeUnit.NANOSECONDS.convert(timeoutMilli, TimeUnit.MILLISECONDS); if (mLoopFailed) { - throw new IllegalStateException( - "Cannot run loop as an exception has occurred previously."); + if (mPriorInterruptedIOException != null) { + throw mPriorInterruptedIOException; + } else { + throw mPriorRuntimeException; + } } if (mLoopRunning) { throw new IllegalStateException( @@ -111,9 +120,15 @@ } else { take(true, timeoutNano - System.nanoTime() + startNano).run(); } - } catch (InterruptedIOException | RuntimeException e) { + } catch (InterruptedIOException e) { mLoopRunning = false; mLoopFailed = true; + mPriorInterruptedIOException = e; + throw e; + } catch (RuntimeException e) { + mLoopRunning = false; + mLoopFailed = true; + mPriorRuntimeException = e; throw e; } }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java index d5d98e2..597ba9e 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
@@ -38,6 +38,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.InterruptedIOException; import java.io.OutputStream; import java.lang.reflect.Method; import java.net.HttpURLConnection; @@ -1402,4 +1403,70 @@ urlConnection.disconnect(); assertTrue(CronetTestUtil.nativeGetTaggedBytes(tag) > priorBytes); } + + @Test + @SmallTest + @Feature({"Cronet"}) + @CompareDefaultWithCronet + public void testIOExceptionErrorRethrown() throws Exception { + // URL that should fail to connect. + URL url = new URL("http://localhost"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + // This should not throw, even though internally it may encounter an exception. + connection.getHeaderField("blah"); + try { + // This should throw an IOException. + connection.getResponseCode(); + fail(); + } catch (IOException e) { + // Expected + } + connection.disconnect(); + } + + @Test + @SmallTest + @Feature({"Cronet"}) + @CompareDefaultWithCronet + public void testIOExceptionInterruptRethrown() throws Exception { + // Older system impls don't reliably respond to interrupt. + if (mTestRule.testingSystemHttpURLConnection() + && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return; + } + ServerSocket hangingServer = new ServerSocket(0); + URL url = new URL("http://localhost:" + hangingServer.getLocalPort()); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + // connect() is non-blocking. + connection.connect(); + FutureTask<IOException> task = new FutureTask<IOException>(new Callable<IOException>() { + @Override + public IOException call() { + // This should not throw, even though internally it may encounter an exception. + connection.getHeaderField("blah"); + try { + // This should throw an InterruptedIOException. + connection.getResponseCode(); + } catch (InterruptedIOException e) { + // Expected + return e; + } catch (IOException e) { + return null; + } + return null; + } + }); + Thread t = new Thread(task); + t.start(); + Socket s = hangingServer.accept(); + hangingServer.close(); + // This will trigger an InterruptException in getHeaderField() and getResponseCode(). + // getHeaderField() should not re-throw it. getResponseCode() should re-throw it as an + // InterruptedIOException. + t.interrupt(); + // Make sure an IOException is thrown. + assertNotNull(task.get()); + s.close(); + connection.disconnect(); + } }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java index 8d1938b..0678fe8a 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/MessageLoopTest.java
@@ -19,6 +19,7 @@ import org.chromium.net.CronetTestRule; import java.io.IOException; +import java.io.InterruptedIOException; import java.net.SocketTimeoutException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -78,7 +79,7 @@ loop.loop(); fail(); } catch (Exception e) { - if (!(e instanceof IllegalStateException)) { + if (!(e instanceof InterruptedIOException)) { fail(); } } @@ -127,7 +128,7 @@ loop.loop(); fail(); } catch (Exception e) { - if (!(e instanceof IllegalStateException)) { + if (!(e instanceof NullPointerException)) { fail(); } }
diff --git a/components/history_strings.grdp b/components/history_strings.grdp index a46b1cd8..463ebd9 100644 --- a/components/history_strings.grdp +++ b/components/history_strings.grdp
@@ -51,7 +51,7 @@ No search results found </message> <if expr="not use_titlecase"> - <message name="IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG" desc="Title of the button that will open the clear browsing data dialog."> + <message name="IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG" desc="Title of the button that will open the clear browsing data dialog [Length: 16em]."> Clear browsing data... </message> </if>
diff --git a/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc b/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc index 15cd48d..265c1d76 100644 --- a/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc +++ b/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc
@@ -137,7 +137,7 @@ std::string response_body = R"( { - "private_topic_name": "test-pr" + "privateTopicName": "test-pr" } )";
diff --git a/components/invalidation/impl/per_user_topic_registration_request.cc b/components/invalidation/impl/per_user_topic_registration_request.cc index a9eef18..353818a 100644 --- a/components/invalidation/impl/per_user_topic_registration_request.cc +++ b/components/invalidation/impl/per_user_topic_registration_request.cc
@@ -17,7 +17,7 @@ namespace { -const char kPrivateTopicNameKey[] = "private_topic_name"; +const char kPrivateTopicNameKey[] = "privateTopicName"; base::Value* GetPrivateTopicName(base::Value* value) { if (!value || !value->is_dict()) {
diff --git a/components/invalidation/impl/per_user_topic_registration_request_unittest.cc b/components/invalidation/impl/per_user_topic_registration_request_unittest.cc index 03b3316a..6c452fb 100644 --- a/components/invalidation/impl/per_user_topic_registration_request_unittest.cc +++ b/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
@@ -124,7 +124,7 @@ .Build(); std::string response_body = R"( { - "private_topic_name": "test-pr" + "privateTopicName": "test-pr" } )"; @@ -166,7 +166,7 @@ .Build(); std::string response_body = R"( { - "private_topic_name": "test-pr" + "privateTopicName": "test-pr" } )";
diff --git a/components/safe_browsing/browser/threat_details.cc b/components/safe_browsing/browser/threat_details.cc index eeda739..5a5dee7 100644 --- a/components/safe_browsing/browser/threat_details.cc +++ b/components/safe_browsing/browser/threat_details.cc
@@ -271,7 +271,7 @@ // don't leak it. class ThreatDetailsFactoryImpl : public ThreatDetailsFactory { public: - ThreatDetails* CreateThreatDetails( + scoped_refptr<ThreatDetails> CreateThreatDetails( BaseUIManager* ui_manager, WebContents* web_contents, const security_interstitials::UnsafeResource& unsafe_resource, @@ -280,10 +280,12 @@ ReferrerChainProvider* referrer_chain_provider, bool trim_to_ad_tags, ThreatDetailsDoneCallback done_callback) override { - return new ThreatDetails(ui_manager, web_contents, unsafe_resource, - url_loader_factory, history_service, - referrer_chain_provider, trim_to_ad_tags, - done_callback); + auto threat_details = base::WrapRefCounted(new ThreatDetails( + ui_manager, web_contents, unsafe_resource, url_loader_factory, + history_service, referrer_chain_provider, trim_to_ad_tags, + done_callback)); + threat_details->StartCollection(); + return threat_details; } private: @@ -299,7 +301,7 @@ // Create a ThreatDetails for the given tab. /* static */ -ThreatDetails* ThreatDetails::NewThreatDetails( +scoped_refptr<ThreatDetails> ThreatDetails::NewThreatDetails( BaseUIManager* ui_manager, WebContents* web_contents, const UnsafeResource& resource, @@ -344,7 +346,6 @@ redirects_collector_ = new ThreatDetailsRedirectsCollector( history_service ? history_service->AsWeakPtr() : base::WeakPtr<history::HistoryService>()); - StartCollection(); } // TODO(lpz): Consider making this constructor delegate to the parameterized one
diff --git a/components/safe_browsing/browser/threat_details.h b/components/safe_browsing/browser/threat_details.h index acea93c2..61db996 100644 --- a/components/safe_browsing/browser/threat_details.h +++ b/components/safe_browsing/browser/threat_details.h
@@ -73,7 +73,7 @@ typedef security_interstitials::UnsafeResource UnsafeResource; // Constructs a new ThreatDetails instance, using the factory. - static ThreatDetails* NewThreatDetails( + static scoped_refptr<ThreatDetails> NewThreatDetails( BaseUIManager* ui_manager, content::WebContents* web_contents, const UnsafeResource& resource, @@ -107,6 +107,7 @@ protected: friend class ThreatDetailsFactoryImpl; friend class TestThreatDetailsFactory; + friend class ThreatDetailsTest; ThreatDetails( BaseUIManager* ui_manager, @@ -133,12 +134,12 @@ // Used to get a pointer to the HTTP cache. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - private: - friend class base::RefCounted<ThreatDetails>; - // Starts the collection of the report. void StartCollection(); + private: + friend class base::RefCounted<ThreatDetails>; + // Whether the url is "public" so we can add it to the report. bool IsReportableUrl(const GURL& url) const; @@ -286,7 +287,7 @@ public: virtual ~ThreatDetailsFactory() {} - virtual ThreatDetails* CreateThreatDetails( + virtual scoped_refptr<ThreatDetails> CreateThreatDetails( BaseUIManager* ui_manager, content::WebContents* web_contents, const security_interstitials::UnsafeResource& unsafe_resource,
diff --git a/components/safe_browsing/triggers/trigger_manager_unittest.cc b/components/safe_browsing/triggers/trigger_manager_unittest.cc index f3f5a725..dc4017c8 100644 --- a/components/safe_browsing/triggers/trigger_manager_unittest.cc +++ b/components/safe_browsing/triggers/trigger_manager_unittest.cc
@@ -40,7 +40,7 @@ public: ~MockThreatDetailsFactory() override {} - ThreatDetails* CreateThreatDetails( + scoped_refptr<ThreatDetails> CreateThreatDetails( BaseUIManager* ui_manager, content::WebContents* web_contents, const security_interstitials::UnsafeResource& unsafe_resource, @@ -49,8 +49,7 @@ ReferrerChainProvider* referrer_chain_provider, bool trim_to_ad_tags, ThreatDetailsDoneCallback done_callback) override { - MockThreatDetails* threat_details = new MockThreatDetails(); - return threat_details; + return base::MakeRefCounted<MockThreatDetails>(); } };
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc index 697cd0f..3e7e59f 100644 --- a/components/sync/driver/sync_driver_switches.cc +++ b/components/sync/driver/sync_driver_switches.cc
@@ -78,4 +78,8 @@ const base::Feature kSyncUSSAutofillWalletData{ "SyncUSSAutofillWalletData", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enable USS implementation of autofill wallet metadata datatype. +const base::Feature kSyncUSSAutofillWalletMetadata{ + "SyncUSSAutofillWalletMetadata", base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace switches
diff --git a/components/sync/driver/sync_driver_switches.h b/components/sync/driver/sync_driver_switches.h index b01df2b2..93a6d36 100644 --- a/components/sync/driver/sync_driver_switches.h +++ b/components/sync/driver/sync_driver_switches.h
@@ -30,6 +30,7 @@ extern const base::Feature kSyncUSSSessions; extern const base::Feature kSyncUSSAutofillProfile; extern const base::Feature kSyncUSSAutofillWalletData; +extern const base::Feature kSyncUSSAutofillWalletMetadata; } // namespace switches
diff --git a/components/viz/common/gpu/context_cache_controller.cc b/components/viz/common/gpu/context_cache_controller.cc index c3a48f5..d49abb7 100644 --- a/components/viz/common/gpu/context_cache_controller.cc +++ b/components/viz/common/gpu/context_cache_controller.cc
@@ -159,11 +159,8 @@ return; } - if (gr_context_) { - // Avoid the more complete GrContext::freeGpuResources, as that evicts - // harder to re-generate Skia caches. - gr_context_->purgeUnlockedResources(false /* scratchResourcesOnly */); - } + if (gr_context_) + gr_context_->freeGpuResources(); // Toggle SetAggressivelyFreeResources to drop command buffer data. context_support_->SetAggressivelyFreeResources(true);
diff --git a/components/webdata_services/web_data_service_wrapper.cc b/components/webdata_services/web_data_service_wrapper.cc index 0287a89..b663e2e5 100644 --- a/components/webdata_services/web_data_service_wrapper.cc +++ b/components/webdata_services/web_data_service_wrapper.cc
@@ -17,6 +17,7 @@ #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h" #include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h" #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h" @@ -95,9 +96,15 @@ ->InjectStartSyncFlare(sync_flare); } - autofill::AutofillWalletMetadataSyncableService:: - CreateForWebDataServiceAndBackend(autofill_web_data.get(), - autofill_backend, app_locale); + if (base::FeatureList::IsEnabled(switches::kSyncUSSAutofillWalletMetadata)) { + autofill::AutofillWalletMetadataSyncBridge:: + CreateForWebDataServiceAndBackend(app_locale, autofill_backend, + autofill_web_data.get()); + } else { + autofill::AutofillWalletMetadataSyncableService:: + CreateForWebDataServiceAndBackend(autofill_web_data.get(), + autofill_backend, app_locale); + } } } // namespace
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 4b67636b..43e712c 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -444,6 +444,8 @@ "background_fetch/storage/get_initialization_data_task.h", "background_fetch/storage/get_metadata_task.cc", "background_fetch/storage/get_metadata_task.h", + "background_fetch/storage/get_registration_task.cc", + "background_fetch/storage/get_registration_task.h", "background_fetch/storage/get_settled_fetches_task.cc", "background_fetch/storage/get_settled_fetches_task.h", "background_fetch/storage/image_helpers.cc",
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc index 4aaa80c..cc2c5f0 100644 --- a/content/browser/background_fetch/background_fetch_context.cc +++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -73,11 +73,9 @@ } for (auto& data : initialization_data) { - CreateController(data.registration_id, data.options, data.icon, - data.ui_title, data.num_completed_requests, - data.num_requests, data.active_fetch_guids, - std::make_unique<BackgroundFetchRegistration>( - std::move(data.registration))); + CreateController(data.registration_id, data.registration, data.options, + data.icon, data.ui_title, data.num_completed_requests, + data.num_requests, data.active_fetch_guids); } } @@ -105,7 +103,7 @@ void BackgroundFetchContext::DidGetRegistration( blink::mojom::BackgroundFetchService::GetRegistrationCallback callback, blink::mojom::BackgroundFetchError error, - std::unique_ptr<BackgroundFetchRegistration> registration) { + const BackgroundFetchRegistration& registration) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (error != blink::mojom::BackgroundFetchError::NONE) { @@ -114,13 +112,15 @@ return; } - DCHECK(registration); + BackgroundFetchRegistration updated_registration(registration); + // The data manager only has the number of bytes from completed downloads, so // augment this with the number of downloaded bytes from in-progress jobs. - DCHECK(job_controllers_.count(registration->unique_id)); - registration->downloaded += - job_controllers_[registration->unique_id]->GetInProgressDownloadedBytes(); - std::move(callback).Run(error, *registration.get()); + DCHECK(job_controllers_.count(registration.unique_id)); + updated_registration.downloaded += + job_controllers_[registration.unique_id]->GetInProgressDownloadedBytes(); + + std::move(callback).Run(error, updated_registration); } void BackgroundFetchContext::StartFetch( @@ -141,8 +141,7 @@ data_manager_->CreateRegistration( registration_id, requests, options, icon, base::BindOnce(&BackgroundFetchContext::DidCreateRegistration, - weak_factory_.GetWeakPtr(), registration_id, options, icon, - requests.size())); + weak_factory_.GetWeakPtr(), registration_id)); } void BackgroundFetchContext::GetIconDisplaySize( @@ -154,35 +153,25 @@ void BackgroundFetchContext::DidCreateRegistration( const BackgroundFetchRegistrationId& registration_id, - const BackgroundFetchOptions& options, - const SkBitmap& icon, - size_t num_requests, blink::mojom::BackgroundFetchError error, - std::unique_ptr<BackgroundFetchRegistration> registration) { + const BackgroundFetchRegistration& registration) { DCHECK_CURRENTLY_ON(BrowserThread::IO); background_fetch::RecordRegistrationCreatedError(error); - if (error != blink::mojom::BackgroundFetchError::NONE) { - DCHECK(fetch_callbacks_.count(registration_id)); - std::move(fetch_callbacks_[registration_id]) - .Run(error, base::nullopt /* BackgroundFetchRegistration */); - fetch_callbacks_.erase(registration_id); + + auto iter = fetch_callbacks_.find(registration_id); + + // The fetch might have been abandoned already if the Service Worker was + // unregistered or corrupted while registration was in progress. + if (iter == fetch_callbacks_.end()) return; - } - if (hang_registration_creation_for_testing_) { - // Hang here, to allow time for testing races. For instance, this helps us - // test the behavior when a service worker gets unregistered before the - // controller can be created. - return; - } + if (error == blink::mojom::BackgroundFetchError::NONE) + std::move(iter->second).Run(error, registration); + else + std::move(iter->second).Run(error, base::nullopt /* registration */); - DCHECK(registration); - - // Create the BackgroundFetchJobController to do the actual fetching. - CreateController(registration_id, options, icon, options.title, - 0u /* num_completed_requests */, num_requests, - {} /* outstanding_guids */, std::move(registration)); + fetch_callbacks_.erase(registration_id); } void BackgroundFetchContext::AddRegistrationObserver( @@ -250,6 +239,29 @@ } } +void BackgroundFetchContext::OnRegistrationCreated( + const BackgroundFetchRegistrationId& registration_id, + const BackgroundFetchRegistration& registration, + const BackgroundFetchOptions& options, + const SkBitmap& icon, + int num_requests) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (hang_registration_creation_for_testing_) { + // Hang here, to allow time for testing races. For instance, this helps us + // test the behavior when a service worker gets unregistered before the + // controller can be created. + return; + } + + // TODO(peter): When this moves to the BackgroundFetchScheduler, only create + // a controller when the background fetch can actually be started. + + CreateController(registration_id, registration, options, icon, options.title, + 0u /* num_completed_requests */, num_requests, + {} /* outstanding_guids */); +} + void BackgroundFetchContext::OnUpdatedUI( const BackgroundFetchRegistrationId& registration_id, const std::string& title) { @@ -274,18 +286,18 @@ void BackgroundFetchContext::CreateController( const BackgroundFetchRegistrationId& registration_id, + const BackgroundFetchRegistration& registration, const BackgroundFetchOptions& options, const SkBitmap& icon, const std::string& ui_title, size_t num_completed_requests, size_t num_requests, - const std::vector<std::string>& outstanding_guids, - std::unique_ptr<BackgroundFetchRegistration> registration) { + const std::vector<std::string>& outstanding_guids) { DCHECK_CURRENTLY_ON(BrowserThread::IO); auto controller = std::make_unique<BackgroundFetchJobController>( - &delegate_proxy_, registration_id, options, icon, - registration->downloaded, scheduler_.get(), + &delegate_proxy_, registration_id, options, icon, registration.downloaded, + scheduler_.get(), // Safe because JobControllers are destroyed before RegistrationNotifier. base::BindRepeating(&BackgroundFetchRegistrationNotifier::Notify, base::Unretained(registration_notifier_.get())), @@ -297,13 +309,6 @@ outstanding_guids, ui_title); scheduler_->AddJobController(controller.get()); job_controllers_.emplace(registration_id.unique_id(), std::move(controller)); - - auto fetch_callback_iter = fetch_callbacks_.find(registration_id); - if (fetch_callback_iter != fetch_callbacks_.end()) { - std::move(fetch_callback_iter->second) - .Run(blink::mojom::BackgroundFetchError::NONE, *registration); - fetch_callbacks_.erase(fetch_callback_iter); - } } void BackgroundFetchContext::Abort(
diff --git a/content/browser/background_fetch/background_fetch_context.h b/content/browser/background_fetch/background_fetch_context.h index a6b05e1..f2ec5e3 100644 --- a/content/browser/background_fetch/background_fetch_context.h +++ b/content/browser/background_fetch/background_fetch_context.h
@@ -114,6 +114,12 @@ blink::mojom::BackgroundFetchService::UpdateUICallback callback); // BackgroundFetchDataManagerObserver implementation. + void OnRegistrationCreated( + const BackgroundFetchRegistrationId& registration_id, + const BackgroundFetchRegistration& registration, + const BackgroundFetchOptions& options, + const SkBitmap& icon, + int num_requests) override; void OnUpdatedUI(const BackgroundFetchRegistrationId& registration_id, const std::string& title) override; void OnServiceWorkerDatabaseCorrupted( @@ -125,6 +131,8 @@ void OnStorageWiped() override; private: + FRIEND_TEST_ALL_PREFIXES(BackgroundFetchServiceTest, + JobsInitializedOnBrowserRestart); friend class BackgroundFetchServiceTest; friend class BackgroundFetchJobControllerTest; friend class base::DeleteHelper<BackgroundFetchContext>; @@ -138,31 +146,27 @@ // Creates a new Job Controller for the given |registration_id| and |options|, // which will start fetching the files that are part of the registration. - void CreateController( - const BackgroundFetchRegistrationId& registration_id, - const BackgroundFetchOptions& options, - const SkBitmap& icon, - const std::string& ui_title, - size_t num_completed_requests, - size_t num_requests, - const std::vector<std::string>& outstanding_guids, - std::unique_ptr<BackgroundFetchRegistration> registration); + void CreateController(const BackgroundFetchRegistrationId& registration_id, + const BackgroundFetchRegistration& registration, + const BackgroundFetchOptions& options, + const SkBitmap& icon, + const std::string& ui_title, + size_t num_completed_requests, + size_t num_requests, + const std::vector<std::string>& outstanding_guids); // Called when an existing registration has been retrieved from the data // manager. If the registration does not exist then |registration| is nullptr. void DidGetRegistration( blink::mojom::BackgroundFetchService::GetRegistrationCallback callback, blink::mojom::BackgroundFetchError error, - std::unique_ptr<BackgroundFetchRegistration> registration); + const BackgroundFetchRegistration& registration); // Called when a new registration has been created by the data manager. void DidCreateRegistration( const BackgroundFetchRegistrationId& registration_id, - const BackgroundFetchOptions& options, - const SkBitmap& icon, - size_t num_requests, blink::mojom::BackgroundFetchError error, - std::unique_ptr<BackgroundFetchRegistration> registration); + const BackgroundFetchRegistration& registration); // Called by a JobController when it finishes processing. Also used to // implement |Abort|.
diff --git a/content/browser/background_fetch/background_fetch_data_manager.cc b/content/browser/background_fetch/background_fetch_data_manager.cc index 97fa8390..b2b3d9e4 100644 --- a/content/browser/background_fetch/background_fetch_data_manager.cc +++ b/content/browser/background_fetch/background_fetch_data_manager.cc
@@ -18,6 +18,7 @@ #include "content/browser/background_fetch/storage/delete_registration_task.h" #include "content/browser/background_fetch/storage/get_developer_ids_task.h" #include "content/browser/background_fetch/storage/get_metadata_task.h" +#include "content/browser/background_fetch/storage/get_registration_task.h" #include "content/browser/background_fetch/storage/get_settled_fetches_task.h" #include "content/browser/background_fetch/storage/mark_registration_for_deletion_task.h" #include "content/browser/background_fetch/storage/mark_request_complete_task.h" @@ -32,34 +33,6 @@ namespace content { -namespace { - -// Helper function to convert a BackgroundFetchRegistration proto into a -// BackgroundFetchRegistration struct, and call the appropriate callback. -void GetRegistrationFromMetadata( - BackgroundFetchDataManager::GetRegistrationCallback callback, - blink::mojom::BackgroundFetchError error, - std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto) { - if (!metadata_proto) { - std::move(callback).Run(error, nullptr); - return; - } - - const auto& registration_proto = metadata_proto->registration(); - auto registration = std::make_unique<BackgroundFetchRegistration>(); - registration->developer_id = registration_proto.developer_id(); - registration->unique_id = registration_proto.unique_id(); - // TODO(crbug.com/774054): Uploads are not yet supported. - registration->upload_total = registration_proto.upload_total(); - registration->uploaded = registration_proto.uploaded(); - registration->download_total = registration_proto.download_total(); - registration->downloaded = registration_proto.downloaded(); - - std::move(callback).Run(error, std::move(registration)); -} - -} // namespace - BackgroundFetchDataManager::BackgroundFetchDataManager( BrowserContext* browser_context, scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, @@ -125,23 +98,8 @@ GetRegistrationCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - auto registration_callback = - base::BindOnce(&GetRegistrationFromMetadata, std::move(callback)); AddDatabaseTask(std::make_unique<background_fetch::CreateMetadataTask>( - this, registration_id, requests, options, icon, - std::move(registration_callback))); -} - -void BackgroundFetchDataManager::GetMetadata( - int64_t service_worker_registration_id, - const url::Origin& origin, - const std::string& developer_id, - GetMetadataCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - AddDatabaseTask(std::make_unique<background_fetch::GetMetadataTask>( - this, service_worker_registration_id, origin, developer_id, - std::move(callback))); + this, registration_id, requests, options, icon, std::move(callback))); } void BackgroundFetchDataManager::GetRegistration( @@ -151,10 +109,9 @@ GetRegistrationCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - auto registration_callback = - base::BindOnce(&GetRegistrationFromMetadata, std::move(callback)); - GetMetadata(service_worker_registration_id, origin, developer_id, - std::move(registration_callback)); + AddDatabaseTask(std::make_unique<background_fetch::GetRegistrationTask>( + this, service_worker_registration_id, origin, developer_id, + std::move(callback))); } void BackgroundFetchDataManager::UpdateRegistrationUI( @@ -174,31 +131,29 @@ auto start_next_request = base::BindOnce( &BackgroundFetchDataManager::AddStartNextPendingRequestTask, - weak_ptr_factory_.GetWeakPtr(), - registration_id.service_worker_registration_id(), std::move(callback)); + weak_ptr_factory_.GetWeakPtr(), registration_id, std::move(callback)); // Get the associated metadata, and add a StartNextPendingRequestTask. - GetMetadata(registration_id.service_worker_registration_id(), - registration_id.origin(), registration_id.developer_id(), - std::move(start_next_request)); + AddDatabaseTask(std::make_unique<background_fetch::GetRegistrationTask>( + this, registration_id.service_worker_registration_id(), + registration_id.origin(), registration_id.developer_id(), + std::move(start_next_request))); } void BackgroundFetchDataManager::AddStartNextPendingRequestTask( - int64_t service_worker_registration_id, + const BackgroundFetchRegistrationId& registration_id, NextRequestCallback callback, blink::mojom::BackgroundFetchError error, - std::unique_ptr<proto::BackgroundFetchMetadata> metadata) { - if (!metadata) { + const BackgroundFetchRegistration& registration) { + if (error != blink::mojom::BackgroundFetchError::NONE) { // Stop giving out requests as registration aborted (or otherwise finished). std::move(callback).Run(nullptr /* request */); return; } - DCHECK_EQ(error, blink::mojom::BackgroundFetchError::NONE); AddDatabaseTask( std::make_unique<background_fetch::StartNextPendingRequestTask>( - this, service_worker_registration_id, std::move(metadata), - std::move(callback))); + this, registration_id, registration, std::move(callback))); } void BackgroundFetchDataManager::MarkRequestAsComplete(
diff --git a/content/browser/background_fetch/background_fetch_data_manager.h b/content/browser/background_fetch/background_fetch_data_manager.h index fd6d233d..6dd5b81 100644 --- a/content/browser/background_fetch/background_fetch_data_manager.h +++ b/content/browser/background_fetch/background_fetch_data_manager.h
@@ -66,12 +66,9 @@ bool /* background_fetch_succeeded */, std::vector<BackgroundFetchSettledFetch>, std::vector<std::unique_ptr<storage::BlobDataHandle>>)>; - using GetMetadataCallback = - base::OnceCallback<void(blink::mojom::BackgroundFetchError, - std::unique_ptr<proto::BackgroundFetchMetadata>)>; using GetRegistrationCallback = base::OnceCallback<void(blink::mojom::BackgroundFetchError, - std::unique_ptr<BackgroundFetchRegistration>)>; + const BackgroundFetchRegistration&)>; using NextRequestCallback = base::OnceCallback<void(scoped_refptr<BackgroundFetchRequestInfo>)>; using NumRequestsCallback = base::OnceCallback<void(size_t)>; @@ -105,12 +102,6 @@ const SkBitmap& icon, GetRegistrationCallback callback); - // Get the BackgroundFetchMetadata. - void GetMetadata(int64_t service_worker_registration_id, - const url::Origin& origin, - const std::string& developer_id, - GetMetadataCallback callback); - // Get the BackgroundFetchRegistration. void GetRegistration(int64_t service_worker_registration_id, const url::Origin& origin, @@ -196,10 +187,10 @@ } void AddStartNextPendingRequestTask( - int64_t service_worker_registration_id, + const BackgroundFetchRegistrationId& registration_id, NextRequestCallback callback, blink::mojom::BackgroundFetchError error, - std::unique_ptr<proto::BackgroundFetchMetadata> metadata); + const BackgroundFetchRegistration& registration); void AddDatabaseTask(std::unique_ptr<background_fetch::DatabaseTask> task);
diff --git a/content/browser/background_fetch/background_fetch_data_manager_observer.h b/content/browser/background_fetch/background_fetch_data_manager_observer.h index 12981a8..1436f40b 100644 --- a/content/browser/background_fetch/background_fetch_data_manager_observer.h +++ b/content/browser/background_fetch/background_fetch_data_manager_observer.h
@@ -5,8 +5,14 @@ #ifndef CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_OBSERVER_H_ #define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_DATA_MANAGER_OBSERVER_H_ +#include <memory> + +class SkBitmap; + namespace content { +struct BackgroundFetchOptions; +struct BackgroundFetchRegistration; class BackgroundFetchRegistrationId; // Observer interface for objects that would like to be notified about changes @@ -14,6 +20,14 @@ // will be invoked on the IO thread. class BackgroundFetchDataManagerObserver { public: + // Called when the Background Fetch |registration| has been created. + virtual void OnRegistrationCreated( + const BackgroundFetchRegistrationId& registration_id, + const BackgroundFetchRegistration& registration, + const BackgroundFetchOptions& options, + const SkBitmap& icon, + int num_requests) = 0; + // Called when the |title| for the Background Fetch |registration_id| has been // updated in the data store. virtual void OnUpdatedUI(const BackgroundFetchRegistrationId& registration_id,
diff --git a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc index ced59107..9ac1b3e 100644 --- a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc +++ b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
@@ -38,6 +38,7 @@ namespace { using background_fetch::BackgroundFetchInitializationData; +using ::testing::_; using ::testing::UnorderedElementsAre; using ::testing::IsEmpty; @@ -63,16 +64,15 @@ std::move(quit_closure).Run(); } -void DidCreateRegistration( - base::Closure quit_closure, - blink::mojom::BackgroundFetchError* out_error, - blink::mojom::BackgroundFetchError error, - std::unique_ptr<BackgroundFetchRegistration> registration) { +void DidCreateRegistration(base::OnceClosure quit_closure, + blink::mojom::BackgroundFetchError* out_error, + blink::mojom::BackgroundFetchError error, + const BackgroundFetchRegistration& registration) { *out_error = error; std::move(quit_closure).Run(); } -void DidGetError(base::Closure quit_closure, +void DidGetError(base::OnceClosure quit_closure, blink::mojom::BackgroundFetchError* out_error, blink::mojom::BackgroundFetchError error) { *out_error = error; @@ -207,14 +207,14 @@ run_loop.Run(); } - std::unique_ptr<BackgroundFetchRegistration> GetRegistration( + BackgroundFetchRegistration GetRegistration( int64_t service_worker_registration_id, const url::Origin& origin, const std::string developer_id, blink::mojom::BackgroundFetchError* out_error) { DCHECK(out_error); - std::unique_ptr<BackgroundFetchRegistration> registration; + BackgroundFetchRegistration registration; base::RunLoop run_loop; background_fetch_data_manager_->GetRegistration( service_worker_registration_id, origin, developer_id, @@ -228,18 +228,16 @@ std::unique_ptr<proto::BackgroundFetchMetadata> GetMetadata( int64_t service_worker_registration_id, - const url::Origin& origin, - const std::string developer_id, - blink::mojom::BackgroundFetchError* out_error) { - DCHECK(out_error); - + const std::string& unique_id) { std::unique_ptr<proto::BackgroundFetchMetadata> metadata; + base::RunLoop run_loop; - background_fetch_data_manager_->GetMetadata( - service_worker_registration_id, origin, developer_id, + embedded_worker_test_helper()->context_wrapper()->GetRegistrationUserData( + service_worker_registration_id, + {background_fetch::RegistrationKey(unique_id)}, base::BindOnce(&BackgroundFetchDataManagerTest::DidGetMetadata, base::Unretained(this), run_loop.QuitClosure(), - out_error, &metadata)); + &metadata)); run_loop.Run(); return metadata; @@ -464,6 +462,12 @@ } // BackgroundFetchDataManagerObserver mocks: + MOCK_METHOD5(OnRegistrationCreated, + void(const BackgroundFetchRegistrationId& registration_id, + const BackgroundFetchRegistration& registration, + const BackgroundFetchOptions& options, + const SkBitmap& icon, + int num_requests)); MOCK_METHOD2(OnUpdatedUI, void(const BackgroundFetchRegistrationId& registration, const std::string& title)); @@ -471,32 +475,29 @@ void(int64_t service_worker_registration_id)); protected: - void DidGetRegistration( - base::Closure quit_closure, - blink::mojom::BackgroundFetchError* out_error, - std::unique_ptr<BackgroundFetchRegistration>* out_registration, - blink::mojom::BackgroundFetchError error, - std::unique_ptr<BackgroundFetchRegistration> registration) { - if (error == blink::mojom::BackgroundFetchError::NONE) { - DCHECK(registration); - } + void DidGetRegistration(base::OnceClosure quit_closure, + blink::mojom::BackgroundFetchError* out_error, + BackgroundFetchRegistration* out_registration, + blink::mojom::BackgroundFetchError error, + const BackgroundFetchRegistration& registration) { *out_error = error; - *out_registration = std::move(registration); + *out_registration = registration; std::move(quit_closure).Run(); } void DidGetMetadata( base::OnceClosure quit_closure, - blink::mojom::BackgroundFetchError* out_error, std::unique_ptr<proto::BackgroundFetchMetadata>* out_metadata, - blink::mojom::BackgroundFetchError error, - std::unique_ptr<proto::BackgroundFetchMetadata> metadata) { - if (error == blink::mojom::BackgroundFetchError::NONE) { - DCHECK(metadata); + const std::vector<std::string>& data, + blink::ServiceWorkerStatusCode status) { + if (status == blink::ServiceWorkerStatusCode::kOk) { + DCHECK_EQ(data.size(), 1u); + + auto metadata = std::make_unique<proto::BackgroundFetchMetadata>(); + if (metadata->ParseFromString(data[0])) + *out_metadata = std::move(metadata); } - *out_error = error; - *out_metadata = std::move(metadata); std::move(quit_closure).Run(); } @@ -596,8 +597,12 @@ EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID); // Creating the initial registration should succeed. - CreateRegistration(registration_id1, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id1, _, _, _, _)); + + CreateRegistration(registration_id1, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } // Different |unique_id|, since this is a new Background Fetch registration, // even though it shares the same |developer_id|. @@ -621,8 +626,12 @@ // And now registering the second registration should work fine, since there // is no longer an *active* registration with the same |developer_id|, even // though the initial registration has not yet been deleted. - CreateRegistration(registration_id2, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _)); + + CreateRegistration(registration_id2, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } } TEST_F(BackgroundFetchDataManagerTest, GetDeveloperIds) { @@ -641,8 +650,12 @@ // Create a single registration. BackgroundFetchRegistrationId registration_id1( sw_id, origin(), kExampleDeveloperId, kExampleUniqueId); - CreateRegistration(registration_id1, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id1, _, _, _, _)); + + CreateRegistration(registration_id1, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } // Verify that the developer ID can be found. developer_ids = GetDeveloperIds(sw_id, origin(), &error); @@ -659,9 +672,12 @@ // Create another registration. BackgroundFetchRegistrationId registration_id2( sw_id, origin(), kAlternativeDeveloperId, kAlternativeUniqueId); - CreateRegistration(registration_id2, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _)); + CreateRegistration(registration_id2, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } // Verify that both developer IDs can be found. developer_ids = GetDeveloperIds(sw_id, origin(), &error); EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); @@ -688,31 +704,34 @@ blink::mojom::BackgroundFetchError error; // Create a single registration. - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } // Verify that the registration can be retrieved. auto registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); - ASSERT_TRUE(registration); - EXPECT_EQ(kExampleUniqueId, registration->unique_id); - EXPECT_EQ(kExampleDeveloperId, registration->developer_id); + + EXPECT_EQ(kExampleUniqueId, registration.unique_id); + EXPECT_EQ(kExampleDeveloperId, registration.developer_id); // Verify that retrieving using the wrong developer id doesn't work. registration = GetRegistration(sw_id, origin(), kAlternativeDeveloperId, &error); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID); - ASSERT_FALSE(registration); RestartDataManagerFromPersistentStorage(); // After a restart, GetRegistration should still find the registration. registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); - ASSERT_TRUE(registration); - EXPECT_EQ(kExampleUniqueId, registration->unique_id); - EXPECT_EQ(kExampleDeveloperId, registration->developer_id); + + EXPECT_EQ(kExampleUniqueId, registration.unique_id); + EXPECT_EQ(kExampleDeveloperId, registration.developer_id); } TEST_F(BackgroundFetchDataManagerTest, GetMetadata) { @@ -727,27 +746,23 @@ blink::mojom::BackgroundFetchError error; // Create a single registration. - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } // Verify that the metadata can be retrieved. - auto metadata = GetMetadata(sw_id, origin(), kExampleDeveloperId, &error); - ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + auto metadata = GetMetadata(sw_id, kExampleUniqueId); ASSERT_TRUE(metadata); EXPECT_EQ(metadata->origin(), origin().Serialize()); EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0); EXPECT_EQ(metadata->num_fetches(), static_cast<int>(requests.size())); - // Verify that retrieving using the wrong developer id doesn't work. - metadata = GetMetadata(sw_id, origin(), kAlternativeDeveloperId, &error); - ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID); - ASSERT_FALSE(metadata); - RestartDataManagerFromPersistentStorage(); // After a restart, GetMetadata should still find the registration. - metadata = GetMetadata(sw_id, origin(), kExampleDeveloperId, &error); - ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + metadata = GetMetadata(sw_id, kExampleUniqueId); ASSERT_TRUE(metadata); EXPECT_EQ(metadata->origin(), origin().Serialize()); EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0); @@ -770,12 +785,15 @@ icon.eraseColor(SK_ColorGREEN); // Create a single registration. - CreateRegistration(registration_id, requests, options, icon, &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, icon, &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } // Verify that the metadata can be retrieved. - auto metadata = GetMetadata(sw_id, origin(), kExampleDeveloperId, &error); - ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + auto metadata = GetMetadata(sw_id, kExampleUniqueId); ASSERT_TRUE(metadata); EXPECT_EQ(metadata->origin(), origin().Serialize()); EXPECT_NE(metadata->creation_microseconds_since_unix_epoch(), 0); @@ -799,8 +817,12 @@ EXPECT_TRUE(GetUIOptions(sw_id).title().empty()); // Create a single registration. - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } // Verify that the title can be retrieved. ASSERT_EQ(GetUIOptions(sw_id).title(), kInitialTitle); @@ -830,8 +852,12 @@ BackgroundFetchOptions options; blink::mojom::BackgroundFetchError error; - CreateRegistration(registration_id1, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id1, _, _, _, _)); + + CreateRegistration(registration_id1, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } RestartDataManagerFromPersistentStorage(); @@ -844,15 +870,15 @@ // |service_worker_registration_id| should yield an error, even after // restarting. CreateRegistration(registration_id2, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::DUPLICATED_DEVELOPER_ID); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::DUPLICATED_DEVELOPER_ID); // Verify that the registration can be retrieved before deletion. auto registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); - ASSERT_TRUE(registration); - EXPECT_EQ(kExampleUniqueId, registration->unique_id); - EXPECT_EQ(kExampleDeveloperId, registration->developer_id); + + EXPECT_EQ(kExampleUniqueId, registration.unique_id); + EXPECT_EQ(kExampleDeveloperId, registration.developer_id); // Deactivating the registration should succeed. MarkRegistrationForDeletion(registration_id1, &error); @@ -861,7 +887,6 @@ // Verify that the registration cannot be retrieved after deletion registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID); - ASSERT_FALSE(registration); RestartDataManagerFromPersistentStorage(); @@ -869,14 +894,17 @@ // a restart. registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ID); - ASSERT_FALSE(registration); // And now registering the second registration should work fine, even after // restarting, since there is no longer an *active* registration with the same // |developer_id|, even though the initial registration has not yet been // deleted. - CreateRegistration(registration_id2, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _)); + + CreateRegistration(registration_id2, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } RestartDataManagerFromPersistentStorage(); @@ -907,8 +935,13 @@ BackgroundFetchOptions options; blink::mojom::BackgroundFetchError error; - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } + EXPECT_EQ( GetRequestStats(sw_id), (ResponseStateStats{2 /* pending_requests */, 0 /* active_requests */, @@ -970,13 +1003,17 @@ BackgroundFetchOptions options; blink::mojom::BackgroundFetchError error; - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } auto registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); - EXPECT_EQ(registration->download_total, 0u); + EXPECT_EQ(registration.download_total, 0u); scoped_refptr<BackgroundFetchRequestInfo> request_info; PopNextRequest(registration_id, &request_info); @@ -986,7 +1023,7 @@ registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); - EXPECT_EQ(registration->download_total, kResponseFileSize); + EXPECT_EQ(registration.download_total, kResponseFileSize); PopNextRequest(registration_id, &request_info); AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(), @@ -995,7 +1032,7 @@ registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); - EXPECT_EQ(registration->download_total, 2 * kResponseFileSize); + EXPECT_EQ(registration.download_total, 2 * kResponseFileSize); PopNextRequest(registration_id, &request_info); AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get(), @@ -1005,7 +1042,7 @@ registration = GetRegistration(sw_id, origin(), kExampleDeveloperId, &error); ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); // |download_total| is unchanged. - EXPECT_EQ(registration->download_total, 2 * kResponseFileSize); + EXPECT_EQ(registration.download_total, 2 * kResponseFileSize); } TEST_F(BackgroundFetchDataManagerTest, WriteToCache) { @@ -1018,9 +1055,12 @@ BackgroundFetchOptions options; blink::mojom::BackgroundFetchError error; + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } scoped_refptr<BackgroundFetchRequestInfo> request_info; PopNextRequest(registration_id, &request_info); @@ -1062,9 +1102,12 @@ BackgroundFetchOptions options; blink::mojom::BackgroundFetchError error; + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); - CreateRegistration(registration_id, {request}, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + CreateRegistration(registration_id, {request}, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } scoped_refptr<BackgroundFetchRequestInfo> request_info; PopNextRequest(registration_id, &request_info); @@ -1095,8 +1138,13 @@ BackgroundFetchRegistrationId registration_id( sw_id, origin(), kExampleDeveloperId, kExampleUniqueId); - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } + EXPECT_EQ( GetRequestStats(sw_id), (ResponseStateStats{2 /* pending_requests */, 0 /* active_requests */, @@ -1147,8 +1195,12 @@ BackgroundFetchOptions options; blink::mojom::BackgroundFetchError error; - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } bool succeeded = false; std::vector<BackgroundFetchSettledFetch> settled_fetches; @@ -1215,8 +1267,12 @@ BackgroundFetchRegistrationId registration_id( sw_id, origin(), kExampleDeveloperId, kExampleUniqueId); - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } for (size_t i = 0; i < requests.size(); i++) { SCOPED_TRACE(i); @@ -1255,8 +1311,12 @@ BackgroundFetchRegistrationId registration_id( sw_id, origin(), kExampleDeveloperId, kExampleUniqueId); - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } for (size_t i = 0; i < requests.size() - 1; i++) { SCOPED_TRACE(i); @@ -1300,8 +1360,12 @@ EXPECT_EQ(0u, GetRegistrationUserDataByKeyPrefix(sw_id, kUserDataPrefix).size()); // Create a registration. - CreateRegistration(registration_id, requests, options, SkBitmap(), &error); - ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } // We expect as many pending entries as there are requests. EXPECT_EQ(requests.size(), @@ -1364,8 +1428,14 @@ SkBitmap icon; icon.allocN32Pixels(42, 42); icon.eraseColor(SK_ColorGREEN); - CreateRegistration(registration_id, requests, options, icon, &error); - ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id, _, _, _, _)); + + CreateRegistration(registration_id, requests, options, icon, &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } + { std::vector<BackgroundFetchInitializationData> data = GetInitializationData(); @@ -1413,8 +1483,13 @@ // Create another registration. BackgroundFetchRegistrationId registration_id2( sw_id, origin(), kAlternativeDeveloperId, kAlternativeUniqueId); - CreateRegistration(registration_id2, requests, options, SkBitmap(), &error); - EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + { + EXPECT_CALL(*this, OnRegistrationCreated(registration_id2, _, _, _, _)); + + CreateRegistration(registration_id2, requests, options, SkBitmap(), &error); + ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); + } + { std::vector<BackgroundFetchInitializationData> data = GetInitializationData(); @@ -1435,11 +1510,15 @@ std::vector<blink::mojom::BackgroundFetchError> errors(5); + // We expect a single successful registration to be created. + EXPECT_CALL(*this, OnRegistrationCreated(_, _, _, _, _)); + const int num_parallel_creates = 5; base::RunLoop run_loop; base::RepeatingClosure quit_once_all_finished_closure = base::BarrierClosure(num_parallel_creates, run_loop.QuitClosure()); + for (int i = 0; i < num_parallel_creates; i++) { // New |unique_id| per iteration, since each is a distinct registration. BackgroundFetchRegistrationId registration_id(
diff --git a/content/browser/background_fetch/background_fetch_service_unittest.cc b/content/browser/background_fetch/background_fetch_service_unittest.cc index 36f5702..9a73efb 100644 --- a/content/browser/background_fetch/background_fetch_service_unittest.cc +++ b/content/browser/background_fetch/background_fetch_service_unittest.cc
@@ -290,9 +290,12 @@ base::RunLoop().RunUntilIdle(); } + protected: + scoped_refptr<BackgroundFetchContext> context_; + private: void DidGetRegistration( - base::Closure quit_closure, + base::OnceClosure quit_closure, blink::mojom::BackgroundFetchError* out_error, BackgroundFetchRegistration* out_registration, blink::mojom::BackgroundFetchError error, @@ -305,15 +308,14 @@ std::move(quit_closure).Run(); } - void DidStartFetch( - base::Closure quit_closure, - blink::mojom::BackgroundFetchError error, - std::unique_ptr<BackgroundFetchRegistration> registration) { + void DidStartFetch(base::OnceClosure quit_closure, + blink::mojom::BackgroundFetchError error, + const BackgroundFetchRegistration& registration) { ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE); std::move(quit_closure).Run(); } - void DidGetError(base::Closure quit_closure, + void DidGetError(base::OnceClosure quit_closure, blink::mojom::BackgroundFetchError* out_error, blink::mojom::BackgroundFetchError error) { *out_error = error; @@ -321,7 +323,7 @@ std::move(quit_closure).Run(); } - void DidGetDeveloperIds(base::Closure quit_closure, + void DidGetDeveloperIds(base::OnceClosure quit_closure, blink::mojom::BackgroundFetchError* out_error, std::vector<std::string>* out_developer_ids, blink::mojom::BackgroundFetchError error, @@ -332,7 +334,6 @@ std::move(quit_closure).Run(); } - scoped_refptr<BackgroundFetchContext> context_; std::unique_ptr<BackgroundFetchServiceImpl> service_; DISALLOW_COPY_AND_ASSIGN(BackgroundFetchServiceTest); @@ -1095,9 +1096,15 @@ .Build())); BackgroundFetchOptions options; - // Only register the Fetch. - StartFetch(service_worker_registration_id, kExampleDeveloperId, requests, - options, SkBitmap()); + // Only register the Fetch. In order to appropriately simulate a browser + // restart, we do not want the fetch to start yet. + { + base::AutoReset<bool> hang_registration_creation_for_testing( + &context_->hang_registration_creation_for_testing_, true); + + StartFetch(service_worker_registration_id, kExampleDeveloperId, requests, + options, SkBitmap()); + } // Simulate browser restart by re-creating |context_| and |service_|. SetUp();
diff --git a/content/browser/background_fetch/storage/create_metadata_task.cc b/content/browser/background_fetch/storage/create_metadata_task.cc index a57d8e6..cab3c9e 100644 --- a/content/browser/background_fetch/storage/create_metadata_task.cc +++ b/content/browser/background_fetch/storage/create_metadata_task.cc
@@ -8,6 +8,8 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "content/browser/background_fetch/background_fetch_data_manager.h" +#include "content/browser/background_fetch/background_fetch_data_manager_observer.h" #include "content/browser/background_fetch/storage/database_helpers.h" #include "content/browser/background_fetch/storage/image_helpers.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" @@ -191,9 +193,20 @@ void CreateMetadataTask::FinishWithError( blink::mojom::BackgroundFetchError error) { - if (error != blink::mojom::BackgroundFetchError::NONE) - metadata_proto_.reset(); - std::move(callback_).Run(error, std::move(metadata_proto_)); + BackgroundFetchRegistration registration; + + if (error == blink::mojom::BackgroundFetchError::NONE) { + DCHECK(metadata_proto_); + + registration = ToBackgroundFetchRegistration(*metadata_proto_); + + for (auto& observer : data_manager()->observers()) { + observer.OnRegistrationCreated(registration_id_, registration, options_, + icon_, requests_.size()); + } + } + + std::move(callback_).Run(error, registration); Finished(); // Destroys |this|. }
diff --git a/content/browser/background_fetch/storage/create_metadata_task.h b/content/browser/background_fetch/storage/create_metadata_task.h index b57d953..11bdea37 100644 --- a/content/browser/background_fetch/storage/create_metadata_task.h +++ b/content/browser/background_fetch/storage/create_metadata_task.h
@@ -17,6 +17,8 @@ namespace content { +struct BackgroundFetchRegistration; + namespace background_fetch { // Creates Background Fetch metadata entries in the database. @@ -24,7 +26,7 @@ public: using CreateMetadataCallback = base::OnceCallback<void(blink::mojom::BackgroundFetchError, - std::unique_ptr<proto::BackgroundFetchMetadata>)>; + const BackgroundFetchRegistration&)>; CreateMetadataTask(DatabaseTaskHost* host, const BackgroundFetchRegistrationId& registration_id,
diff --git a/content/browser/background_fetch/storage/database_helpers.cc b/content/browser/background_fetch/storage/database_helpers.cc index 44152e8..7079357 100644 --- a/content/browser/background_fetch/storage/database_helpers.cc +++ b/content/browser/background_fetch/storage/database_helpers.cc
@@ -5,6 +5,7 @@ #include "content/browser/background_fetch/storage/database_helpers.h" #include "base/strings/string_number_conversions.h" +#include "content/browser/background_fetch/background_fetch.pb.h" namespace content { @@ -87,6 +88,21 @@ return DatabaseStatus::kFailed; } +BackgroundFetchRegistration ToBackgroundFetchRegistration( + const proto::BackgroundFetchMetadata& metadata_proto) { + const auto& registration_proto = metadata_proto.registration(); + + BackgroundFetchRegistration registration; + registration.developer_id = registration_proto.developer_id(); + registration.unique_id = registration_proto.unique_id(); + registration.upload_total = registration_proto.upload_total(); + registration.uploaded = registration_proto.uploaded(); + registration.download_total = registration_proto.download_total(); + registration.downloaded = registration_proto.downloaded(); + + return registration; +} + } // namespace background_fetch } // namespace content
diff --git a/content/browser/background_fetch/storage/database_helpers.h b/content/browser/background_fetch/storage/database_helpers.h index 459a558..215fb56 100644 --- a/content/browser/background_fetch/storage/database_helpers.h +++ b/content/browser/background_fetch/storage/database_helpers.h
@@ -7,11 +7,17 @@ #include <string> +#include "content/common/background_fetch/background_fetch_types.h" +#include "content/common/content_export.h" #include "content/common/service_worker/service_worker_types.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" namespace content { +namespace proto { +class BackgroundFetchMetadata; +} + namespace background_fetch { // The database schema is content/browser/background_fetch/storage/README.md. @@ -32,7 +38,7 @@ // Database Keys. std::string ActiveRegistrationUniqueIdKey(const std::string& developer_id); -std::string RegistrationKey(const std::string& unique_id); +CONTENT_EXPORT std::string RegistrationKey(const std::string& unique_id); std::string UIOptionsKey(const std::string& unique_id); @@ -54,6 +60,10 @@ DatabaseStatus ToDatabaseStatus(blink::ServiceWorkerStatusCode status); +// Converts the |metadata_proto| to a BackgroundFetchRegistration object. +BackgroundFetchRegistration ToBackgroundFetchRegistration( + const proto::BackgroundFetchMetadata& metadata_proto); + } // namespace background_fetch } // namespace content
diff --git a/content/browser/background_fetch/storage/get_registration_task.cc b/content/browser/background_fetch/storage/get_registration_task.cc new file mode 100644 index 0000000..e8cbc868 --- /dev/null +++ b/content/browser/background_fetch/storage/get_registration_task.cc
@@ -0,0 +1,59 @@ +// 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 "content/browser/background_fetch/storage/get_registration_task.h" + +#include "content/browser/background_fetch/background_fetch.pb.h" +#include "content/browser/background_fetch/storage/database_helpers.h" +#include "content/browser/background_fetch/storage/get_metadata_task.h" + +namespace content { + +namespace background_fetch { + +GetRegistrationTask::GetRegistrationTask(DatabaseTaskHost* host, + int64_t service_worker_registration_id, + const url::Origin& origin, + const std::string& developer_id, + GetRegistrationCallback callback) + : DatabaseTask(host), + service_worker_registration_id_(service_worker_registration_id), + origin_(origin), + developer_id_(developer_id), + callback_(std::move(callback)), + weak_factory_(this) {} + +GetRegistrationTask::~GetRegistrationTask() = default; + +void GetRegistrationTask::Start() { + AddSubTask(std::make_unique<GetMetadataTask>( + this, service_worker_registration_id_, origin_, developer_id_, + base::BindOnce(&GetRegistrationTask::DidGetMetadata, + weak_factory_.GetWeakPtr()))); +} + +void GetRegistrationTask::DidGetMetadata( + blink::mojom::BackgroundFetchError error, + std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto) { + metadata_proto_ = std::move(metadata_proto); + FinishWithError(error); +} + +void GetRegistrationTask::FinishWithError( + blink::mojom::BackgroundFetchError error) { + BackgroundFetchRegistration registration; + + if (error == blink::mojom::BackgroundFetchError::NONE) { + DCHECK(metadata_proto_); + + registration = ToBackgroundFetchRegistration(*metadata_proto_); + } + + std::move(callback_).Run(error, registration); + Finished(); // Destroys |this|. +} + +} // namespace background_fetch + +} // namespace content
diff --git a/content/browser/background_fetch/storage/get_registration_task.h b/content/browser/background_fetch/storage/get_registration_task.h new file mode 100644 index 0000000..1178529 --- /dev/null +++ b/content/browser/background_fetch/storage/get_registration_task.h
@@ -0,0 +1,66 @@ +// 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 CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_REGISTRATION_TASK_H_ +#define CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_REGISTRATION_TASK_H_ + +#include <memory> +#include <string> + +#include "base/callback_forward.h" +#include "content/browser/background_fetch/storage/database_task.h" +#include "third_party/blink/public/common/service_worker/service_worker_status_code.h" +#include "url/origin.h" + +namespace content { + +namespace proto { +class BackgroundFetchMetadata; +} + +namespace background_fetch { + +// Gets an active Background Fetch metadata entry from the database. +class GetRegistrationTask : public DatabaseTask { + public: + using GetRegistrationCallback = + base::OnceCallback<void(blink::mojom::BackgroundFetchError, + const BackgroundFetchRegistration&)>; + + GetRegistrationTask(DatabaseTaskHost* host, + int64_t service_worker_registration_id, + const url::Origin& origin, + const std::string& developer_id, + GetRegistrationCallback callback); + + ~GetRegistrationTask() override; + + // DatabaseTask implementation: + void Start() override; + + private: + void DidGetMetadata( + blink::mojom::BackgroundFetchError error, + std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto); + + void FinishWithError(blink::mojom::BackgroundFetchError error) override; + + int64_t service_worker_registration_id_; + url::Origin origin_; + std::string developer_id_; + + GetRegistrationCallback callback_; + + std::unique_ptr<proto::BackgroundFetchMetadata> metadata_proto_; + + base::WeakPtrFactory<GetRegistrationTask> weak_factory_; // Keep as last. + + DISALLOW_COPY_AND_ASSIGN(GetRegistrationTask); +}; + +} // namespace background_fetch + +} // namespace content + +#endif // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_REGISTRATION_TASK_H_
diff --git a/content/browser/background_fetch/storage/start_next_pending_request_task.cc b/content/browser/background_fetch/storage/start_next_pending_request_task.cc index 1cc5c79..d0ae4e3 100644 --- a/content/browser/background_fetch/storage/start_next_pending_request_task.cc +++ b/content/browser/background_fetch/storage/start_next_pending_request_task.cc
@@ -15,15 +15,15 @@ StartNextPendingRequestTask::StartNextPendingRequestTask( DatabaseTaskHost* host, - int64_t service_worker_registration_id, - std::unique_ptr<proto::BackgroundFetchMetadata> metadata, + const BackgroundFetchRegistrationId& registration_id, + const BackgroundFetchRegistration& registration, NextRequestCallback callback) : DatabaseTask(host), - service_worker_registration_id_(service_worker_registration_id), - metadata_(std::move(metadata)), + registration_id_(registration_id), + registration_(registration), callback_(std::move(callback)), weak_factory_(this) { - DCHECK(metadata_); + DCHECK(!registration_id_.is_null()); } StartNextPendingRequestTask::~StartNextPendingRequestTask() = default; @@ -34,8 +34,8 @@ void StartNextPendingRequestTask::GetPendingRequests() { service_worker_context()->GetRegistrationUserDataByKeyPrefix( - service_worker_registration_id_, - PendingRequestKeyPrefix(metadata_->registration().unique_id()), + registration_id_.service_worker_registration_id(), + PendingRequestKeyPrefix(registration_.unique_id), base::BindOnce(&StartNextPendingRequestTask::DidGetPendingRequests, weak_factory_.GetWeakPtr())); } @@ -59,7 +59,7 @@ if (!pending_request_.ParseFromString(data.front())) { // Service Worker database has been corrupted. Abandon fetches. - AbandonFetches(service_worker_registration_id_); + AbandonFetches(registration_id_.service_worker_registration_id()); FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR); return; } @@ -67,7 +67,7 @@ // Make sure there isn't already an Active Request. // This might happen if the browser is killed in-between writes. service_worker_context()->GetRegistrationUserData( - service_worker_registration_id_, + registration_id_.service_worker_registration_id(), {ActiveRequestKey(pending_request_.unique_id(), pending_request_.request_index())}, base::BindOnce(&StartNextPendingRequestTask::DidFindActiveRequest, @@ -88,7 +88,7 @@ // We already stored the active request. if (!active_request_.ParseFromString(data.front())) { // Service worker database has been corrupted. Abandon fetches. - AbandonFetches(service_worker_registration_id_); + AbandonFetches(registration_id_.service_worker_registration_id()); FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR); return; } @@ -109,7 +109,8 @@ pending_request_.release_serialized_request()); service_worker_context()->StoreRegistrationUserData( - service_worker_registration_id_, GURL(metadata_->origin()), + registration_id_.service_worker_registration_id(), + registration_id_.origin().GetURL(), {{ActiveRequestKey(active_request_.unique_id(), active_request_.request_index()), active_request_.SerializeAsString()}}, @@ -143,7 +144,7 @@ // Delete the pending request. service_worker_context()->ClearRegistrationUserData( - service_worker_registration_id_, + registration_id_.service_worker_registration_id(), {PendingRequestKey(pending_request_.unique_id(), pending_request_.request_index())}, base::BindOnce(&StartNextPendingRequestTask::DidDeletePendingRequest,
diff --git a/content/browser/background_fetch/storage/start_next_pending_request_task.h b/content/browser/background_fetch/storage/start_next_pending_request_task.h index 89ae0fb..fcef4e4 100644 --- a/content/browser/background_fetch/storage/start_next_pending_request_task.h +++ b/content/browser/background_fetch/storage/start_next_pending_request_task.h
@@ -9,6 +9,7 @@ #include "content/browser/background_fetch/background_fetch.pb.h" #include "content/browser/background_fetch/background_fetch_request_info.h" #include "content/browser/background_fetch/storage/database_task.h" +#include "content/common/background_fetch/background_fetch_types.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" namespace content { @@ -24,8 +25,8 @@ StartNextPendingRequestTask( DatabaseTaskHost* host, - int64_t service_worker_registration_id, - std::unique_ptr<proto::BackgroundFetchMetadata> metadata, + const BackgroundFetchRegistrationId& registration_id, + const BackgroundFetchRegistration& registration, NextRequestCallback callback); ~StartNextPendingRequestTask() override; @@ -52,8 +53,8 @@ void FinishWithError(blink::mojom::BackgroundFetchError error) override; - int64_t service_worker_registration_id_; - std::unique_ptr<proto::BackgroundFetchMetadata> metadata_; + BackgroundFetchRegistrationId registration_id_; + BackgroundFetchRegistration registration_; NextRequestCallback callback_; // protos don't support move semantics, so these class members will be used
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.h b/content/browser/renderer_host/browser_compositor_view_mac.h index 46be85e..254be13 100644 --- a/content/browser/renderer_host/browser_compositor_view_mac.h +++ b/content/browser/renderer_host/browser_compositor_view_mac.h
@@ -148,7 +148,7 @@ bool ForceNewSurfaceForTesting(); - ui::Compositor* GetCompositorForTesting() const; + ui::Compositor* GetCompositor() const; private: // ui::LayerObserver implementation:
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.mm b/content/browser/renderer_host/browser_compositor_view_mac.mm index 9bb2156..5bf4dbf4 100644 --- a/content/browser/renderer_host/browser_compositor_view_mac.mm +++ b/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -487,7 +487,9 @@ SetParentUiLayer(nullptr); } -ui::Compositor* BrowserCompositorMac::GetCompositorForTesting() const { +ui::Compositor* BrowserCompositorMac::GetCompositor() const { + if (parent_ui_layer_) + return parent_ui_layer_->GetCompositor(); if (recyclable_compositor_) return recyclable_compositor_->compositor(); return nullptr;
diff --git a/content/browser/renderer_host/input/fling_scheduler_mac.mm b/content/browser/renderer_host/input/fling_scheduler_mac.mm index f2ac740b..83959b3e 100644 --- a/content/browser/renderer_host/input/fling_scheduler_mac.mm +++ b/content/browser/renderer_host/input/fling_scheduler_mac.mm
@@ -21,14 +21,10 @@ // RWHV_child_frame doesn't have DelegatedFrameHost with ui::Compositor. if (host_->GetView()->IsRenderWidgetHostViewChildFrame()) return nullptr; - - // TODO(sahel): Uncomment this once Viz is ready on Mac. - // https://crbug.com/833985 - /* RenderWidgetHostViewMac* view = + RenderWidgetHostViewMac* view = static_cast<RenderWidgetHostViewMac*>(host_->GetView()); if (view->BrowserCompositor()) - return view->BrowserCompositor()->Compositor(); - } */ + return view->BrowserCompositor()->GetCompositor(); return nullptr; }
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 5e77b36..3454038 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2830,14 +2830,22 @@ return; } + // Consider any bitmaps registered with the old CompositorFrameSink as gone, + // they will be re-registered on the newly requested CompositorFrameSink if + // they are meant to be used still. https://crbug.com/862584. + for (const auto& id : owned_bitmaps_) + shared_bitmap_manager_->ChildDeletedSharedBitmap(id); + owned_bitmaps_.clear(); + if (compositor_frame_sink_binding_.is_bound()) compositor_frame_sink_binding_.Close(); compositor_frame_sink_binding_.Bind( std::move(compositor_frame_sink_request), BrowserMainLoop::GetInstance()->GetResizeTaskRunner()); - if (view_) + if (view_) { view_->DidCreateNewRendererCompositorFrameSink( compositor_frame_sink_client.get()); + } renderer_compositor_frame_sink_ = std::move(compositor_frame_sink_client); }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 0916857..0eec5c7 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -2339,11 +2339,14 @@ GetInputMethod()->OnTextInputTypeChanged(this); const TextInputState* state = text_input_manager_->GetTextInputState(); - if (state && state->show_ime_if_needed && - state->type != ui::TEXT_INPUT_TYPE_NONE && - state->mode != ui::TEXT_INPUT_MODE_NONE && - GetInputMethod()->GetTextInputClient() == this) { - GetInputMethod()->ShowVirtualKeyboardIfEnabled(); + if (state && state->type != ui::TEXT_INPUT_TYPE_NONE && + state->mode != ui::TEXT_INPUT_MODE_NONE) { + if (state->show_ime_if_needed && + GetInputMethod()->GetTextInputClient() == this) + GetInputMethod()->ShowVirtualKeyboardIfEnabled(); + // Ensure that accessibility events are fired when the selection location + // moves from UI back to content. + text_input_manager->NotifySelectionBoundsChanged(updated_view); } if (auto* render_widget_host = updated_view->host()) {
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc index 0f9d0a1c..940d9c1 100644 --- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc +++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -751,73 +751,75 @@ ProcessMouseWheelEvent(mouse_wheel_event, *event->latency()); } } - return; - } - - gfx::Point center(gfx::Rect(window_->bounds().size()).CenterPoint()); - - // If we receive non client mouse messages while we are in the locked state - // it probably means that the mouse left the borders of our window and - // needs to be moved back to the center. - if (event->flags() & ui::EF_IS_NON_CLIENT) { - // TODO(jonross): ideally this would not be done for mus (crbug.com/621412) - MoveCursorToCenter(); - return; - } - - blink::WebMouseEvent mouse_event = - ui::MakeWebMouseEvent(*event, base::Bind(&GetScreenLocationFromEvent)); - - bool is_move_to_center_event = - (event->type() == ui::ET_MOUSE_MOVED || - event->type() == ui::ET_MOUSE_DRAGGED) && - mouse_event.PositionInWidget().x == center.x() && - mouse_event.PositionInWidget().y == center.y(); - - // For fractional scale factors, the conversion from pixels to dip and - // vice versa could result in off by 1 or 2 errors which hurts us because - // we want to avoid sending the artificial move to center event to the - // renderer. Sending the move to center to the renderer cause the cursor - // to bounce around the center of the screen leading to the lock operation - // not working correctly. - // Workaround is to treat a mouse move or drag event off by at most 2 px - // from the center as a move to center event. - if (synthetic_move_sent_ && - IsFractionalScaleFactor(host_view_->current_device_scale_factor())) { - if (event->type() == ui::ET_MOUSE_MOVED || - event->type() == ui::ET_MOUSE_DRAGGED) { - if ((std::abs(mouse_event.PositionInWidget().x - center.x()) <= 2) && - (std::abs(mouse_event.PositionInWidget().y - center.y()) <= 2)) { - is_move_to_center_event = true; - } - } - } - - ModifyEventMovementAndCoords(*event, &mouse_event); - - bool should_not_forward = is_move_to_center_event && synthetic_move_sent_; - if (should_not_forward) { - synthetic_move_sent_ = false; } else { - // Check if the mouse has reached the border and needs to be centered. - if (ShouldMoveToCenter()) + gfx::Point center(gfx::Rect(window_->bounds().size()).CenterPoint()); + + // If we receive non client mouse messages while we are in the locked state + // it probably means that the mouse left the borders of our window and + // needs to be moved back to the center. + if (event->flags() & ui::EF_IS_NON_CLIENT) { + // TODO(jonross): ideally this would not be done for mus + // (crbug.com/621412) MoveCursorToCenter(); - bool is_selection_popup = NeedsInputGrab(popup_child_host_view_); - // Forward event to renderer. - if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) && - !(event->flags() & ui::EF_FROM_TOUCH)) { - if (ShouldRouteEvent(event)) { - host_->delegate()->GetInputEventRouter()->RouteMouseEvent( - host_view_, &mouse_event, *event->latency()); - } else { - ProcessMouseEvent(mouse_event, *event->latency()); + return; + } + + blink::WebMouseEvent mouse_event = + ui::MakeWebMouseEvent(*event, base::Bind(&GetScreenLocationFromEvent)); + + bool is_move_to_center_event = + (event->type() == ui::ET_MOUSE_MOVED || + event->type() == ui::ET_MOUSE_DRAGGED) && + mouse_event.PositionInWidget().x == center.x() && + mouse_event.PositionInWidget().y == center.y(); + + // For fractional scale factors, the conversion from pixels to dip and + // vice versa could result in off by 1 or 2 errors which hurts us because + // we want to avoid sending the artificial move to center event to the + // renderer. Sending the move to center to the renderer cause the cursor + // to bounce around the center of the screen leading to the lock operation + // not working correctly. + // Workaround is to treat a mouse move or drag event off by at most 2 px + // from the center as a move to center event. + if (synthetic_move_sent_ && + IsFractionalScaleFactor(host_view_->current_device_scale_factor())) { + if (event->type() == ui::ET_MOUSE_MOVED || + event->type() == ui::ET_MOUSE_DRAGGED) { + if ((std::abs(mouse_event.PositionInWidget().x - center.x()) <= 2) && + (std::abs(mouse_event.PositionInWidget().y - center.y()) <= 2)) { + is_move_to_center_event = true; + } } - // Ensure that we get keyboard focus on mouse down as a plugin window - // may have grabbed keyboard focus. - if (event->type() == ui::ET_MOUSE_PRESSED) - SetKeyboardFocus(); + } + + ModifyEventMovementAndCoords(*event, &mouse_event); + + bool should_not_forward = is_move_to_center_event && synthetic_move_sent_; + if (should_not_forward) { + synthetic_move_sent_ = false; + } else { + // Check if the mouse has reached the border and needs to be centered. + if (ShouldMoveToCenter()) + MoveCursorToCenter(); + bool is_selection_popup = NeedsInputGrab(popup_child_host_view_); + // Forward event to renderer. + if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) && + !(event->flags() & ui::EF_FROM_TOUCH)) { + if (ShouldRouteEvent(event)) { + host_->delegate()->GetInputEventRouter()->RouteMouseEvent( + host_view_, &mouse_event, *event->latency()); + } else { + ProcessMouseEvent(mouse_event, *event->latency()); + } + // Ensure that we get keyboard focus on mouse down as a plugin window + // may have grabbed keyboard focus. + if (event->type() == ui::ET_MOUSE_PRESSED) + SetKeyboardFocus(); + } } } + if (!ShouldGenerateAppCommand(event)) + event->SetHandled(); } void RenderWidgetHostViewEventHandler::ModifyEventMovementAndCoords(
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 4fceb1a..a97ff3eb 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
@@ -1837,11 +1837,11 @@ TEST_F(RenderWidgetHostViewMacTest, ClearCompositorFrame) { BrowserCompositorMac* browser_compositor = rwhv_mac_->BrowserCompositor(); - ui::Compositor* ui_compositor = browser_compositor->GetCompositorForTesting(); + ui::Compositor* ui_compositor = browser_compositor->GetCompositor(); EXPECT_NE(ui_compositor, nullptr); EXPECT_TRUE(ui_compositor->IsLocked()); rwhv_mac_->ClearCompositorFrame(); - EXPECT_EQ(browser_compositor->GetCompositorForTesting(), ui_compositor); + EXPECT_EQ(browser_compositor->GetCompositor(), ui_compositor); EXPECT_FALSE(ui_compositor->IsLocked()); }
diff --git a/content/browser/renderer_host/text_input_manager.cc b/content/browser/renderer_host/text_input_manager.cc index 24f32e72..ce3a5ff8 100644 --- a/content/browser/renderer_host/text_input_manager.cc +++ b/content/browser/renderer_host/text_input_manager.cc
@@ -209,6 +209,11 @@ selection_region_map_[view].first_selection_rect.set_size( params.anchor_rect.size()); + NotifySelectionBoundsChanged(view); +} + +void TextInputManager::NotifySelectionBoundsChanged( + RenderWidgetHostViewBase* view) { for (auto& observer : observer_list_) observer.OnSelectionBoundsChanged(this, view); }
diff --git a/content/browser/renderer_host/text_input_manager.h b/content/browser/renderer_host/text_input_manager.h index 8e4ecfe..d145a992 100644 --- a/content/browser/renderer_host/text_input_manager.h +++ b/content/browser/renderer_host/text_input_manager.h
@@ -184,6 +184,10 @@ void SelectionBoundsChanged(RenderWidgetHostViewBase* view, const ViewHostMsg_SelectionBounds_Params& params); + // Notify observers that the selection bounds have been updated. This is also + // called when a view with a selection is reactivated. + void NotifySelectionBoundsChanged(RenderWidgetHostViewBase* view); + // Called when the composition range and/or character bounds have changed. void ImeCompositionRangeChanged( RenderWidgetHostViewBase* view,
diff --git a/content/browser/service_worker/service_worker_consts.cc b/content/browser/service_worker/service_worker_consts.cc index 0a6663f..b149396 100644 --- a/content/browser/service_worker/service_worker_consts.cc +++ b/content/browser/service_worker/service_worker_consts.cc
@@ -46,6 +46,9 @@ const char ServiceWorkerConsts::kShutdownErrorMessage[] = "The Service Worker system has shutdown."; +const char ServiceWorkerConsts::kUpdateTimeoutErrorMesage[] = + "Service worker self-update limit exceeded."; + const char ServiceWorkerConsts::kUserDeniedPermissionMessage[] = "The user denied permission to use Service Worker.";
diff --git a/content/browser/service_worker/service_worker_consts.h b/content/browser/service_worker/service_worker_consts.h index d119a47..1eab9d5 100644 --- a/content/browser/service_worker/service_worker_consts.h +++ b/content/browser/service_worker/service_worker_consts.h
@@ -21,6 +21,7 @@ static const char kNoDocumentURLErrorMessage[]; static const char kSetNavigationPreloadHeaderErrorPrefix[]; static const char kShutdownErrorMessage[]; + static const char kUpdateTimeoutErrorMesage[]; static const char kUserDeniedPermissionMessage[]; };
diff --git a/content/browser/service_worker/service_worker_object_host.cc b/content/browser/service_worker/service_worker_object_host.cc index 49b03786..cd4f6ea5 100644 --- a/content/browser/service_worker/service_worker_object_host.cc +++ b/content/browser/service_worker/service_worker_object_host.cc
@@ -19,7 +19,7 @@ namespace { using StatusCallback = base::OnceCallback<void(blink::ServiceWorkerStatusCode)>; -using SetExtendableMessageEventSourceCallback = +using PrepareExtendableMessageEventCallback = base::OnceCallback<bool(mojom::ExtendableMessageEventPtr*)>; void DispatchExtendableMessageEventAfterStartWorker( @@ -28,7 +28,7 @@ const url::Origin& source_origin, const base::Optional<base::TimeDelta>& timeout, StatusCallback callback, - SetExtendableMessageEventSourceCallback set_source_callback, + PrepareExtendableMessageEventCallback prepare_callback, blink::ServiceWorkerStatusCode start_worker_status) { if (start_worker_status != blink::ServiceWorkerStatusCode::kOk) { std::move(callback).Run(start_worker_status); @@ -38,7 +38,7 @@ mojom::ExtendableMessageEventPtr event = mojom::ExtendableMessageEvent::New(); event->message = std::move(message); event->source_origin = source_origin; - if (!std::move(set_source_callback).Run(&event)) { + if (!std::move(prepare_callback).Run(&event)) { std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorFailed); return; } @@ -62,7 +62,7 @@ const url::Origin& source_origin, const base::Optional<base::TimeDelta>& timeout, StatusCallback callback, - SetExtendableMessageEventSourceCallback set_source_callback) { + PrepareExtendableMessageEventCallback prepare_callback) { // If not enough time is left to actually process the event don't even // bother starting the worker and sending the event. if (timeout && *timeout < base::TimeDelta::FromMilliseconds(100)) { @@ -74,27 +74,42 @@ ServiceWorkerMetrics::EventType::MESSAGE, base::BindOnce(&DispatchExtendableMessageEventAfterStartWorker, worker, std::move(message), source_origin, timeout, - std::move(callback), std::move(set_source_callback))); + std::move(callback), std::move(prepare_callback))); } -bool SetSourceClientInfo( +bool PrepareExtendableMessageEventFromClient( + base::WeakPtr<ServiceWorkerContextCore> context, + int64_t registration_id, blink::mojom::ServiceWorkerClientInfoPtr source_client_info, mojom::ExtendableMessageEventPtr* event) { + if (!context) { + return false; + } DCHECK(source_client_info && !source_client_info->client_uuid.empty()); (*event)->source_info_for_client = std::move(source_client_info); // Hide the client url if the client has a unique origin. if ((*event)->source_origin.unique()) (*event)->source_info_for_client->url = GURL(); + + // Reset |registration->self_update_delay| iff postMessage is coming from a + // client, to prevent workers from postMessage to another version to reset + // the delay (https://crbug.com/805496). + ServiceWorkerRegistration* registration = + context->GetLiveRegistration(registration_id); + DCHECK(registration) << "running workers should have a live registration"; + registration->set_self_update_delay(base::TimeDelta()); + return true; } // The output |event| must be sent over Mojo immediately after this function // returns. See ServiceWorkerObjectHost::CreateCompleteObjectInfoToSend() for // details. -bool SetSourceServiceWorkerInfo(scoped_refptr<ServiceWorkerVersion> worker, - base::WeakPtr<ServiceWorkerProviderHost> - source_service_worker_provider_host, - mojom::ExtendableMessageEventPtr* event) { +bool PrepareExtendableMessageEventFromServiceWorker( + scoped_refptr<ServiceWorkerVersion> worker, + base::WeakPtr<ServiceWorkerProviderHost> + source_service_worker_provider_host, + mojom::ExtendableMessageEventPtr* event) { // The service worker execution context may have been destroyed by the time we // get here. if (!source_service_worker_provider_host) @@ -121,11 +136,16 @@ } void DispatchExtendableMessageEventFromClient( + base::WeakPtr<ServiceWorkerContextCore> context, scoped_refptr<ServiceWorkerVersion> worker, blink::TransferableMessage message, const url::Origin& source_origin, StatusCallback callback, blink::mojom::ServiceWorkerClientInfoPtr source_client_info) { + if (!context) { + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort); + return; + } // |source_client_info| may be null if a client sent the message but its // info could not be retrieved. if (!source_client_info) { @@ -136,7 +156,8 @@ StartWorkerToDispatchExtendableMessageEvent( worker, std::move(message), source_origin, base::nullopt /* timeout */, std::move(callback), - base::BindOnce(&SetSourceClientInfo, std::move(source_client_info))); + base::BindOnce(&PrepareExtendableMessageEventFromClient, context, + worker->registration_id(), std::move(source_client_info))); } void DispatchExtendableMessageEventFromServiceWorker( @@ -156,7 +177,7 @@ source_service_worker_provider_host->provider_type()); StartWorkerToDispatchExtendableMessageEvent( worker, std::move(message), source_origin, timeout, std::move(callback), - base::BindOnce(&SetSourceServiceWorkerInfo, worker, + base::BindOnce(&PrepareExtendableMessageEventFromServiceWorker, worker, source_service_worker_provider_host)); } @@ -261,8 +282,8 @@ case blink::mojom::ServiceWorkerProviderType::kForWindow: service_worker_client_utils::GetClient( provider_host_, - base::BindOnce(&DispatchExtendableMessageEventFromClient, version_, - std::move(message), provider_origin_, + base::BindOnce(&DispatchExtendableMessageEventFromClient, context_, + version_, std::move(message), provider_origin_, std::move(callback))); return; case blink::mojom::ServiceWorkerProviderType::kForServiceWorker: {
diff --git a/content/browser/service_worker/service_worker_registration.h b/content/browser/service_worker/service_worker_registration.h index e579f31c..2b9d3a29 100644 --- a/content/browser/service_worker/service_worker_registration.h +++ b/content/browser/service_worker/service_worker_registration.h
@@ -15,6 +15,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" +#include "base/time/time.h" #include "content/browser/service_worker/service_worker_version.h" #include "content/common/content_export.h" #include "content/common/service_worker/service_worker_types.h" @@ -162,6 +163,13 @@ base::Time last_update_check() const { return last_update_check_; } void set_last_update_check(base::Time last) { last_update_check_ = last; } + // The delay for self-updating service workers, to prevent them from running + // forever (see https://crbug.com/805496). + base::TimeDelta self_update_delay() const { return self_update_delay_; } + void set_self_update_delay(const base::TimeDelta& delay) { + self_update_delay_ = delay; + } + // Unsets the version and deletes its resources. Also deletes this // registration from storage if there is no longer a stored version. void DeleteVersion(const scoped_refptr<ServiceWorkerVersion>& version); @@ -227,6 +235,7 @@ bool should_activate_when_ready_; blink::mojom::NavigationPreloadState navigation_preload_state_; base::Time last_update_check_; + base::TimeDelta self_update_delay_; int64_t resources_total_size_bytes_; // This registration is the primary owner of these versions.
diff --git a/content/browser/service_worker/service_worker_registration_object_host.cc b/content/browser/service_worker/service_worker_registration_object_host.cc index 4e758bf3..5466cd6 100644 --- a/content/browser/service_worker/service_worker_registration_object_host.cc +++ b/content/browser/service_worker/service_worker_registration_object_host.cc
@@ -4,11 +4,13 @@ #include "content/browser/service_worker/service_worker_registration_object_host.h" +#include "base/time/time.h" #include "content/browser/service_worker/service_worker_consts.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_object_host.h" #include "content/browser/service_worker/service_worker_provider_host.h" #include "content/common/service_worker/service_worker_utils.h" +#include "content/public/browser/browser_thread.h" #include "net/http/http_util.h" #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h" @@ -16,6 +18,9 @@ namespace { +constexpr base::TimeDelta kSelfUpdateDelay = base::TimeDelta::FromSeconds(30); +constexpr base::TimeDelta kMaxSelfUpdateDelay = base::TimeDelta::FromMinutes(3); + // Returns an object info to send over Mojo. The info must be sent immediately. // See ServiceWorkerObjectHost::CreateCompleteObjectInfoToSend() for details. blink::mojom::ServiceWorkerObjectInfoPtr CreateCompleteObjectInfoToSend( @@ -28,6 +33,45 @@ return service_worker_object_host->CreateCompleteObjectInfoToSend(); } +void ExecuteUpdate(base::WeakPtr<ServiceWorkerContextCore> context, + int64_t registration_id, + bool force_bypass_cache, + bool skip_script_comparison, + ServiceWorkerContextCore::UpdateCallback callback, + blink::ServiceWorkerStatusCode status) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (status != blink::ServiceWorkerStatusCode::kOk) { + // The delay was already very long and update() is rejected immediately. + DCHECK_EQ(blink::ServiceWorkerStatusCode::kErrorTimeout, status); + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorTimeout, + ServiceWorkerConsts::kUpdateTimeoutErrorMesage, + registration_id); + return; + } + + if (!context) { + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort, + ServiceWorkerConsts::kShutdownErrorMessage, + registration_id); + return; + } + + ServiceWorkerRegistration* registration = + context->GetLiveRegistration(registration_id); + if (!registration) { + // The service worker is no longer running, so update() won't be rejected. + // We still run the callback so the caller knows. + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorTimeout, + ServiceWorkerConsts::kUpdateTimeoutErrorMesage, + registration_id); + return; + } + + context->UpdateServiceWorker(registration, force_bypass_cache, + skip_script_comparison, std::move(callback)); +} + } // anonymous namespace ServiceWorkerRegistrationObjectHost::ServiceWorkerRegistrationObjectHost( @@ -116,14 +160,58 @@ return; } - context_->UpdateServiceWorker( - registration_.get(), false /* force_bypass_cache */, - false /* skip_script_comparison */, - base::AdaptCallbackForRepeating( + DelayUpdate( + provider_host_->provider_type(), registration_.get(), + provider_host_->running_hosted_version(), + base::BindOnce( + &ExecuteUpdate, context_, registration_->id(), + false /* force_bypass_cache */, false /* skip_script_comparison */, base::BindOnce(&ServiceWorkerRegistrationObjectHost::UpdateComplete, weak_ptr_factory_.GetWeakPtr(), std::move(callback)))); } +void ServiceWorkerRegistrationObjectHost::DelayUpdate( + blink::mojom::ServiceWorkerProviderType provider_type, + ServiceWorkerRegistration* registration, + ServiceWorkerVersion* version, + StatusCallback update_function) { + DCHECK(registration); + + if (provider_type != + blink::mojom::ServiceWorkerProviderType::kForServiceWorker || + (version && version->HasControllee())) { + // Don't delay update() if called by non-workers or by workers with + // controllees. + std::move(update_function).Run(blink::ServiceWorkerStatusCode::kOk); + return; + } + + base::TimeDelta delay = registration->self_update_delay(); + if (delay > kMaxSelfUpdateDelay) { + std::move(update_function) + .Run(blink::ServiceWorkerStatusCode::kErrorTimeout); + return; + } + + if (delay < kSelfUpdateDelay) { + registration->set_self_update_delay(kSelfUpdateDelay); + } else { + registration->set_self_update_delay(delay * 2); + } + + if (delay < base::TimeDelta::Min()) { + // Only enforce the delay of update() iff |delay| exists. + std::move(update_function).Run(blink::ServiceWorkerStatusCode::kOk); + return; + } + + BrowserThread::PostDelayedTask( + BrowserThread::IO, FROM_HERE, + base::BindOnce(std::move(update_function), + blink::ServiceWorkerStatusCode::kOk), + delay); +} + void ServiceWorkerRegistrationObjectHost::Unregister( UnregisterCallback callback) { if (!CanServeRegistrationObjectHostMethods( @@ -302,6 +390,7 @@ waiting = CreateCompleteObjectInfoToSend(provider_host_, waiting_version); if (changed_mask.active_changed()) active = CreateCompleteObjectInfoToSend(provider_host_, active_version); + DCHECK(remote_registration_); remote_registration_->SetVersionAttributes( changed_mask.changed(), std::move(installing), std::move(waiting),
diff --git a/content/browser/service_worker/service_worker_registration_object_host.h b/content/browser/service_worker/service_worker_registration_object_host.h index b96daf0..cfca9b43 100644 --- a/content/browser/service_worker/service_worker_registration_object_host.h +++ b/content/browser/service_worker/service_worker_registration_object_host.h
@@ -17,6 +17,9 @@ #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h" namespace content { +namespace service_worker_registration_unittest { +class ServiceWorkerRegistrationObjectHostTest; +} // namespace service_worker_registration_unittest class ServiceWorkerContextCore; class ServiceWorkerVersion; @@ -46,6 +49,12 @@ ServiceWorkerRegistration* registration() { return registration_.get(); } private: + friend class service_worker_registration_unittest:: + ServiceWorkerRegistrationObjectHostTest; + + using StatusCallback = + base::OnceCallback<void(blink::ServiceWorkerStatusCode status)>; + // ServiceWorkerRegistration::Listener overrides. void OnVersionAttributesChanged( ServiceWorkerRegistration* registration, @@ -68,6 +77,20 @@ const std::string& value, SetNavigationPreloadHeaderCallback callback) override; + // Delays an update if it is called by a worker without controllee, to prevent + // workers from running forever (see https://crbug.com/805496). + // Calls |update_function| with blink::ServiceWorkerStatusCode::kOk if the + // update should procceed, and blink::ServiceWorkerStatusCode::kTimeout + // otherwise. + // If there is no delay, or if the delay is very long, |update_function| is + // executed synchronously (before this method returns). + // + // TODO(falken): See if tests can call |Update| directly, then this separate + // function isn't needed. + static void DelayUpdate(blink::mojom::ServiceWorkerProviderType provider_type, + ServiceWorkerRegistration* registration, + ServiceWorkerVersion* version, + StatusCallback update_function); // Called back from ServiceWorkerContextCore when an update is complete. void UpdateComplete(UpdateCallback callback, blink::ServiceWorkerStatusCode status,
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc index 59a6e79..beed04a 100644 --- a/content/browser/service_worker/service_worker_registration_unittest.cc +++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -698,6 +698,27 @@ return error; } + blink::ServiceWorkerStatusCode CallDelayUpdate( + blink::mojom::ServiceWorkerProviderType provider_type, + ServiceWorkerRegistration* registration, + ServiceWorkerVersion* version) { + base::Optional<blink::ServiceWorkerStatusCode> status; + base::RunLoop run_loop; + ServiceWorkerRegistrationObjectHost::DelayUpdate( + blink::mojom::ServiceWorkerProviderType::kForServiceWorker, + registration, version, + base::BindOnce( + [](base::Optional<blink::ServiceWorkerStatusCode>* out_status, + base::OnceClosure callback, + blink::ServiceWorkerStatusCode status) { + *out_status = status; + std::move(callback).Run(); + }, + &status, run_loop.QuitClosure())); + run_loop.Run(); + return status.value(); + } + blink::mojom::ServiceWorkerErrorType CallUnregister( blink::mojom::ServiceWorkerRegistrationObjectHost* registration_host) { blink::mojom::ServiceWorkerErrorType error = @@ -730,21 +751,21 @@ return status.value(); } - int64_t SetUpRegistration(const GURL& scope, const GURL& script_url) { - storage()->LazyInitializeForTest(base::DoNothing()); - base::RunLoop().RunUntilIdle(); - - // Prepare ServiceWorkerRegistration. + scoped_refptr<ServiceWorkerRegistration> CreateRegistration( + const GURL& scope) { blink::mojom::ServiceWorkerRegistrationOptions options; options.scope = scope; - scoped_refptr<ServiceWorkerRegistration> registration = - base::MakeRefCounted<ServiceWorkerRegistration>( - options, storage()->NewRegistrationId(), context()->AsWeakPtr()); - // Prepare ServiceWorkerVersion. + return base::MakeRefCounted<ServiceWorkerRegistration>( + options, storage()->NewRegistrationId(), context()->AsWeakPtr()); + } + + scoped_refptr<ServiceWorkerVersion> CreateVersion( + ServiceWorkerRegistration* registration, + const GURL& script_url) { scoped_refptr<ServiceWorkerVersion> version = - base::MakeRefCounted<ServiceWorkerVersion>( - registration.get(), script_url, storage()->NewVersionId(), - context()->AsWeakPtr()); + base::MakeRefCounted<ServiceWorkerVersion>(registration, script_url, + storage()->NewVersionId(), + context()->AsWeakPtr()); std::vector<ServiceWorkerDatabase::ResourceRecord> records; records.push_back(WriteToDiskCacheSync( storage(), version->script_url(), storage()->NewResourceId(), @@ -755,13 +776,26 @@ version->set_fetch_handler_existence( ServiceWorkerVersion::FetchHandlerExistence::EXISTS); version->SetStatus(ServiceWorkerVersion::INSTALLING); + return version; + } + + int64_t SetUpRegistration(const GURL& scope, const GURL& script_url) { + storage()->LazyInitializeForTest(base::DoNothing()); + base::RunLoop().RunUntilIdle(); + + // Prepare ServiceWorkerRegistration and ServiceWorkerVersion. + scoped_refptr<ServiceWorkerRegistration> registration = + CreateRegistration(scope); + scoped_refptr<ServiceWorkerVersion> version = + CreateVersion(registration.get(), script_url); + // Make the registration findable via storage functions. bool called = false; blink::ServiceWorkerStatusCode status = blink::ServiceWorkerStatusCode::kErrorFailed; - storage()->StoreRegistration(registration.get(), version.get(), - base::AdaptCallbackForRepeating(base::BindOnce( - &SaveStatusCallback, &called, &status))); + storage()->StoreRegistration( + registration.get(), version.get(), + base::BindOnce(&SaveStatusCallback, &called, &status)); base::RunLoop().RunUntilIdle(); EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status); @@ -893,6 +927,102 @@ SetBrowserClientForTesting(old_browser_client); } +TEST_F(ServiceWorkerRegistrationObjectHostTest, Update_NoDelayFromControllee) { + const GURL kScope("https://www.example.com/"); + const GURL kScriptUrl("https://www.example.com/sw.js"); + int64_t registration_id = SetUpRegistration(kScope, kScriptUrl); + const int64_t kProviderId = 99; // Dummy value + ServiceWorkerRemoteProviderEndpoint remote_endpoint = + PrepareProviderHost(kProviderId, kScope); + blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedPtr + registration_host_ptr; + + blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info = + GetRegistrationFromRemote(remote_endpoint.host_ptr()->get(), kScope); + registration_host_ptr.Bind(std::move(info->host_ptr_info)); + // Ignore the messages to the registration object, otherwise the callbacks + // issued from |registration_host_ptr| may wait for receiving the messages to + // |info->request|. + info->request = nullptr; + + // Get registration and set |self_update_delay| to zero. + ServiceWorkerRegistration* registration = + context()->GetLiveRegistration(registration_id); + ASSERT_TRUE(registration); + registration->set_self_update_delay(base::TimeDelta()); + EXPECT_EQ(base::TimeDelta(), registration->self_update_delay()); + + EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone, + CallUpdate(registration_host_ptr.get())); + EXPECT_EQ(base::TimeDelta(), registration->self_update_delay()); +} + +TEST_F(ServiceWorkerRegistrationObjectHostTest, + Update_DelayFromWorkerWithoutControllee) { + const GURL kScope("https://www.example.com/"); + const GURL kScriptUrl("https://www.example.com/sw.js"); + scoped_refptr<ServiceWorkerRegistration> registration = + CreateRegistration(kScope); + scoped_refptr<ServiceWorkerVersion> version = + CreateVersion(registration.get(), kScriptUrl); + + // Initially set |self_update_delay| to zero. + registration->set_self_update_delay(base::TimeDelta()); + EXPECT_EQ(base::TimeDelta(), registration->self_update_delay()); + + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, + CallDelayUpdate( + blink::mojom::ServiceWorkerProviderType::kForServiceWorker, + registration.get(), version.get())); + EXPECT_LT(base::TimeDelta(), registration->self_update_delay()); + + // TODO(falken): Add a test verifying that a delayed update will be executed + // eventually. + + // Set |self_update_delay| to a time so that update() will reject immediately. + registration->set_self_update_delay(base::TimeDelta::FromMinutes(5)); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorTimeout, + CallDelayUpdate( + blink::mojom::ServiceWorkerProviderType::kForServiceWorker, + registration.get(), version.get())); + EXPECT_LE(base::TimeDelta::FromMinutes(5), registration->self_update_delay()); +} + +TEST_F(ServiceWorkerRegistrationObjectHostTest, + Update_NoDelayFromWorkerWithControllee) { + const GURL kScope("https://www.example.com/"); + const GURL kScriptUrl("https://www.example.com/sw.js"); + const int64_t kProviderId = 99; // Dummy value + scoped_refptr<ServiceWorkerRegistration> registration = + CreateRegistration(kScope); + scoped_refptr<ServiceWorkerVersion> version = + CreateVersion(registration.get(), kScriptUrl); + ServiceWorkerRemoteProviderEndpoint remote_endpoint; + std::unique_ptr<ServiceWorkerProviderHost> host = CreateProviderHostForWindow( + helper_->mock_render_process_id(), kProviderId, + true /* is_parent_frame_secure */, context()->AsWeakPtr(), + &remote_endpoint); + host->SetDocumentUrl(kScope); + version->AddControllee(host.get()); + + // Initially set |self_update_delay| to zero. + registration->set_self_update_delay(base::TimeDelta()); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, + CallDelayUpdate( + blink::mojom::ServiceWorkerProviderType::kForServiceWorker, + registration.get(), version.get())); + EXPECT_EQ(base::TimeDelta(), registration->self_update_delay()); + + // Set |self_update_delay| to a time so that update() will reject immediately + // if the worker doesn't have at least one controlee. + registration->set_self_update_delay(base::TimeDelta::FromMinutes(5)); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, + CallDelayUpdate( + blink::mojom::ServiceWorkerProviderType::kForServiceWorker, + registration.get(), version.get())); + EXPECT_EQ(base::TimeDelta::FromMinutes(5), registration->self_update_delay()); +} + TEST_F(ServiceWorkerRegistrationObjectHostTest, Unregister_Success) { const GURL kScope("https://www.example.com/"); const GURL kScriptUrl("https://www.example.com/sw.js");
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 4dbeba6..b9ae2602 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -538,6 +538,21 @@ << "Event of type " << static_cast<int>(event_type) << " can only be dispatched to an active worker: " << status(); + if (event_type != ServiceWorkerMetrics::EventType::INSTALL && + event_type != ServiceWorkerMetrics::EventType::ACTIVATE && + event_type != ServiceWorkerMetrics::EventType::MESSAGE) { + // Reset the self-update delay iff this is not an event that can triggered + // by a service worker itself. Otherwise, service workers can use update() + // to keep running forever via install and activate events, or postMessage() + // between themselves to reset the delay via message event. + // postMessage() resets the delay in ServiceWorkerObjectHost, iff it didn't + // come from a service worker. + ServiceWorkerRegistration* registration = + context_->GetLiveRegistration(registration_id_); + DCHECK(registration) << "running workers should have a live registration"; + registration->set_self_update_delay(base::TimeDelta()); + } + auto request = std::make_unique<InflightRequest>( std::move(error_callback), clock_->Now(), tick_clock_->NowTicks(), event_type); @@ -669,6 +684,12 @@ RestartTick(&idle_time_); ClearTick(&no_controllees_time_); + ServiceWorkerRegistration* registration = + context_->GetLiveRegistration(registration_id_); + if (registration) { + registration->set_self_update_delay(base::TimeDelta()); + } + // Notify observers asynchronously for consistency with RemoveControllee. base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE,
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc index 2b3f970..dbd520b0 100644 --- a/content/browser/service_worker/service_worker_version_unittest.cc +++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -773,6 +773,42 @@ EXPECT_EQ(run_time, version_->update_timer_.desired_run_time()); } +// Tests the delay mechanism for self-updating service workers, to prevent +// them from running forever (see https://crbug.com/805496). +TEST_F(ServiceWorkerVersionTest, ResetUpdateDelay) { + const base::TimeDelta kMinute = base::TimeDelta::FromMinutes(1); + const base::TimeDelta kNoDelay = base::TimeDelta(); + + // Initialize the delay. + version_->SetStatus(ServiceWorkerVersion::ACTIVATED); + registration_->SetActiveVersion(version_); + registration_->set_self_update_delay(kMinute); + + // Events that can be triggered by a worker should not reset the delay. + // See the comment in ServiceWorkerVersion::StartRequestWithCustomTimeout. + SimulateDispatchEvent(ServiceWorkerMetrics::EventType::INSTALL); + SimulateDispatchEvent(ServiceWorkerMetrics::EventType::ACTIVATE); + SimulateDispatchEvent(ServiceWorkerMetrics::EventType::MESSAGE); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(kMinute, registration_->self_update_delay()); + + // Events that can only be triggered externally reset the delay. + // Repeat the test for several such events. + SimulateDispatchEvent(ServiceWorkerMetrics::EventType::SYNC); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(kNoDelay, registration_->self_update_delay()); + + registration_->set_self_update_delay(kMinute); + SimulateDispatchEvent(ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(kNoDelay, registration_->self_update_delay()); + + registration_->set_self_update_delay(kMinute); + SimulateDispatchEvent(ServiceWorkerMetrics::EventType::PUSH); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(kNoDelay, registration_->self_update_delay()); +} + TEST_F(ServiceWorkerVersionTest, UpdateCachedMetadata) { CachedMetadataUpdateListener listener; version_->AddObserver(&listener);
diff --git a/content/browser/web_contents/web_contents_view_mac.mm b/content/browser/web_contents/web_contents_view_mac.mm index f14cb05..94848b56 100644 --- a/content/browser/web_contents/web_contents_view_mac.mm +++ b/content/browser/web_contents/web_contents_view_mac.mm
@@ -450,15 +450,13 @@ } void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) { + parent_ui_layer_ = parent_ui_layer; // Remove any child NSViews that have been destroyed. for (auto iter = child_views_.begin(); iter != child_views_.end();) { - auto iter_next = iter; - iter_next++; if (*iter) - (*iter)->SetParentUiLayer(parent_ui_layer); + (*iter++)->SetParentUiLayer(parent_ui_layer); else - child_views_.erase(iter); - iter = iter_next; + iter = child_views_.erase(iter); } }
diff --git a/content/browser/webauth/authenticator_type_converters.h b/content/browser/webauth/authenticator_type_converters.h index cc4a53d..4d4847b 100644 --- a/content/browser/webauth/authenticator_type_converters.h +++ b/content/browser/webauth/authenticator_type_converters.h
@@ -8,7 +8,7 @@ #include <vector> #include "device/fido/authenticator_selection_criteria.h" -#include "device/fido/fido_cable_discovery.h" +#include "device/fido/cable/fido_cable_discovery.h" #include "device/fido/fido_transport_protocol.h" #include "device/fido/public_key_credential_descriptor.h" #include "device/fido/public_key_credential_params.h"
diff --git a/content/renderer/webclipboard_impl_browsertest.cc b/content/renderer/webclipboard_impl_browsertest.cc index 181dfe0..870a090 100644 --- a/content/renderer/webclipboard_impl_browsertest.cc +++ b/content/renderer/webclipboard_impl_browsertest.cc
@@ -22,7 +22,13 @@ ~WebClipboardImplTest() override = default; }; -IN_PROC_BROWSER_TEST_F(WebClipboardImplTest, PasteRTF) { +#if defined(OS_CHROMEOS) +// Test is flaky on ChromeOS (https://crbug.com/867339). +#define MAYBE_PasteRTF DISABLED_PasteRTF +#else +#define MAYBE_PasteRTF PasteRTF +#endif +IN_PROC_BROWSER_TEST_F(WebClipboardImplTest, MAYBE_PasteRTF) { BrowserTestClipboardScope clipboard; const std::string rtf_content = "{\\rtf1\\ansi Hello, {\\b world.}}";
diff --git a/device/BUILD.gn b/device/BUILD.gn index 21cd7e4e..a36c191 100644 --- a/device/BUILD.gn +++ b/device/BUILD.gn
@@ -67,12 +67,12 @@ "fido/ble/fido_ble_connection_unittest.cc", "fido/ble/fido_ble_device_unittest.cc", "fido/ble/fido_ble_frames_unittest.cc", + "fido/cable/fido_cable_device_unittest.cc", + "fido/cable/fido_cable_discovery_unittest.cc", + "fido/cable/fido_cable_handshake_handler_unittest.cc", "fido/ctap_request_unittest.cc", "fido/ctap_response_unittest.cc", "fido/fake_fido_discovery_unittest.cc", - "fido/fido_cable_device_unittest.cc", - "fido/fido_cable_discovery_unittest.cc", - "fido/fido_cable_handshake_handler_unittest.cc", "fido/fido_discovery_unittest.cc", "fido/fido_parsing_utils_unittest.cc", "fido/fido_request_handler_unittest.cc",
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn index 6efd796..ac443f8a 100644 --- a/device/fido/BUILD.gn +++ b/device/fido/BUILD.gn
@@ -39,6 +39,12 @@ "ble/fido_ble_transaction.h", "ble/fido_ble_uuids.cc", "ble/fido_ble_uuids.h", + "cable/fido_cable_device.cc", + "cable/fido_cable_device.h", + "cable/fido_cable_discovery.cc", + "cable/fido_cable_discovery.h", + "cable/fido_cable_handshake_handler.cc", + "cable/fido_cable_handshake_handler.h", "ctap2_device_operation.h", "ctap_empty_authenticator_request.cc", "ctap_empty_authenticator_request.h", @@ -54,12 +60,6 @@ "fido_attestation_statement.cc", "fido_attestation_statement.h", "fido_authenticator.h", - "fido_cable_device.cc", - "fido_cable_device.h", - "fido_cable_discovery.cc", - "fido_cable_discovery.h", - "fido_cable_handshake_handler.cc", - "fido_cable_handshake_handler.h", "fido_constants.cc", "fido_constants.h", "fido_device.cc", @@ -239,7 +239,7 @@ fuzzer_test("fido_cable_handshake_handler_fuzzer") { sources = [ - "fido_cable_handshake_handler_fuzzer.cc", + "cable/fido_cable_handshake_handler_fuzzer.cc", ] deps = [ ":fido",
diff --git a/device/fido/fido_cable_device.cc b/device/fido/cable/fido_cable_device.cc similarity index 98% rename from device/fido/fido_cable_device.cc rename to device/fido/cable/fido_cable_device.cc index a0581df1..4eccfe35 100644 --- a/device/fido/fido_cable_device.cc +++ b/device/fido/cable/fido_cable_device.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_cable_device.h" +#include "device/fido/cable/fido_cable_device.h" #include <utility> @@ -128,9 +128,9 @@ FROM_HERE, base::BindOnce(std::move(callback), base::nullopt)); state_ = State::kDeviceError; return; - } + } - ++encryption_data_->write_sequence_num; + ++encryption_data_->write_sequence_num; AddToPendingFrames(FidoBleDeviceCommand::kMsg, std::move(command), std::move(callback));
diff --git a/device/fido/fido_cable_device.h b/device/fido/cable/fido_cable_device.h similarity index 94% rename from device/fido/fido_cable_device.h rename to device/fido/cable/fido_cable_device.h index 9475ada..137055f 100644 --- a/device/fido/fido_cable_device.h +++ b/device/fido/cable/fido_cable_device.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_CABLE_DEVICE_H_ -#define DEVICE_FIDO_FIDO_CABLE_DEVICE_H_ +#ifndef DEVICE_FIDO_CABLE_FIDO_CABLE_DEVICE_H_ +#define DEVICE_FIDO_CABLE_FIDO_CABLE_DEVICE_H_ #include <array> #include <memory> @@ -76,4 +76,4 @@ } // namespace device -#endif // DEVICE_FIDO_FIDO_CABLE_DEVICE_H_ +#endif // DEVICE_FIDO_CABLE_FIDO_CABLE_DEVICE_H_
diff --git a/device/fido/fido_cable_device_unittest.cc b/device/fido/cable/fido_cable_device_unittest.cc similarity index 99% rename from device/fido/fido_cable_device_unittest.cc rename to device/fido/cable/fido_cable_device_unittest.cc index ab51af3..8cd0f968 100644 --- a/device/fido/fido_cable_device_unittest.cc +++ b/device/fido/cable/fido_cable_device_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_cable_device.h" +#include "device/fido/cable/fido_cable_device.h" #include <array> #include <limits>
diff --git a/device/fido/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc similarity index 98% rename from device/fido/fido_cable_discovery.cc rename to device/fido/cable/fido_cable_discovery.cc index f6e0ddb..158cd92 100644 --- a/device/fido/fido_cable_discovery.cc +++ b/device/fido/cable/fido_cable_discovery.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_cable_discovery.h" +#include "device/fido/cable/fido_cable_discovery.h" #include <algorithm> #include <memory> @@ -18,8 +18,8 @@ #include "device/bluetooth/bluetooth_discovery_session.h" #include "device/bluetooth/bluetooth_uuid.h" #include "device/fido/ble/fido_ble_uuids.h" -#include "device/fido/fido_cable_device.h" -#include "device/fido/fido_cable_handshake_handler.h" +#include "device/fido/cable/fido_cable_device.h" +#include "device/fido/cable/fido_cable_handshake_handler.h" #include "device/fido/fido_parsing_utils.h" namespace device {
diff --git a/device/fido/fido_cable_discovery.h b/device/fido/cable/fido_cable_discovery.h similarity index 96% rename from device/fido/fido_cable_discovery.h rename to device/fido/cable/fido_cable_discovery.h index 2107095..02c5cb8 100644 --- a/device/fido/fido_cable_discovery.h +++ b/device/fido/cable/fido_cable_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_CABLE_DISCOVERY_H_ -#define DEVICE_FIDO_FIDO_CABLE_DISCOVERY_H_ +#ifndef DEVICE_FIDO_CABLE_FIDO_CABLE_DISCOVERY_H_ +#define DEVICE_FIDO_CABLE_FIDO_CABLE_DISCOVERY_H_ #include <stdint.h> @@ -117,4 +117,4 @@ } // namespace device -#endif // DEVICE_FIDO_FIDO_CABLE_DISCOVERY_H_ +#endif // DEVICE_FIDO_CABLE_FIDO_CABLE_DISCOVERY_H_
diff --git a/device/fido/fido_cable_discovery_unittest.cc b/device/fido/cable/fido_cable_discovery_unittest.cc similarity index 99% rename from device/fido/fido_cable_discovery_unittest.cc rename to device/fido/cable/fido_cable_discovery_unittest.cc index 8d64848..dc69e63 100644 --- a/device/fido/fido_cable_discovery_unittest.cc +++ b/device/fido/cable/fido_cable_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_cable_discovery.h" +#include "device/fido/cable/fido_cable_discovery.h" #include <algorithm> #include <memory> @@ -17,7 +17,7 @@ #include "device/bluetooth/test/mock_bluetooth_adapter.h" #include "device/fido/ble/fido_ble_device.h" #include "device/fido/ble/fido_ble_uuids.h" -#include "device/fido/fido_cable_handshake_handler.h" +#include "device/fido/cable/fido_cable_handshake_handler.h" #include "device/fido/fido_parsing_utils.h" #include "device/fido/mock_fido_discovery_observer.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/device/fido/fido_cable_handshake_handler.cc b/device/fido/cable/fido_cable_handshake_handler.cc similarity index 97% rename from device/fido/fido_cable_handshake_handler.cc rename to device/fido/cable/fido_cable_handshake_handler.cc index a47c5d0..966a476 100644 --- a/device/fido/fido_cable_handshake_handler.cc +++ b/device/fido/cable/fido_cable_handshake_handler.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_cable_handshake_handler.h" +#include "device/fido/cable/fido_cable_handshake_handler.h" #include <algorithm> #include <utility> @@ -14,7 +14,7 @@ #include "crypto/hkdf.h" #include "crypto/hmac.h" #include "crypto/random.h" -#include "device/fido/fido_cable_device.h" +#include "device/fido/cable/fido_cable_device.h" #include "device/fido/fido_constants.h" #include "device/fido/fido_parsing_utils.h"
diff --git a/device/fido/fido_cable_handshake_handler.h b/device/fido/cable/fido_cable_handshake_handler.h similarity index 91% rename from device/fido/fido_cable_handshake_handler.h rename to device/fido/cable/fido_cable_handshake_handler.h index fd764e53..175b55d 100644 --- a/device/fido/fido_cable_handshake_handler.h +++ b/device/fido/cable/fido_cable_handshake_handler.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_CABLE_HANDSHAKE_HANDLER_H_ -#define DEVICE_FIDO_FIDO_CABLE_HANDSHAKE_HANDLER_H_ +#ifndef DEVICE_FIDO_CABLE_FIDO_CABLE_HANDSHAKE_HANDLER_H_ +#define DEVICE_FIDO_CABLE_FIDO_CABLE_HANDSHAKE_HANDLER_H_ #include <stdint.h> @@ -59,4 +59,4 @@ } // namespace device -#endif // DEVICE_FIDO_FIDO_CABLE_HANDSHAKE_HANDLER_H_ +#endif // DEVICE_FIDO_CABLE_FIDO_CABLE_HANDSHAKE_HANDLER_H_
diff --git a/device/fido/fido_cable_handshake_handler_fuzzer.cc b/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc similarity index 91% rename from device/fido/fido_cable_handshake_handler_fuzzer.cc rename to device/fido/cable/fido_cable_handshake_handler_fuzzer.cc index 64a9a7a..35a4351 100644 --- a/device/fido/fido_cable_handshake_handler_fuzzer.cc +++ b/device/fido/cable/fido_cable_handshake_handler_fuzzer.cc
@@ -8,8 +8,8 @@ #include <array> #include "base/containers/span.h" -#include "device/fido/fido_cable_device.h" -#include "device/fido/fido_cable_handshake_handler.h" +#include "device/fido/cable/fido_cable_device.h" +#include "device/fido/cable/fido_cable_handshake_handler.h" #include "device/fido/fido_constants.h" namespace {
diff --git a/device/fido/fido_cable_handshake_handler_unittest.cc b/device/fido/cable/fido_cable_handshake_handler_unittest.cc similarity index 98% rename from device/fido/fido_cable_handshake_handler_unittest.cc rename to device/fido/cable/fido_cable_handshake_handler_unittest.cc index 376eb20..b2e2c08b 100644 --- a/device/fido/fido_cable_handshake_handler_unittest.cc +++ b/device/fido/cable/fido_cable_handshake_handler_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_cable_handshake_handler.h" +#include "device/fido/cable/fido_cable_handshake_handler.h" #include <array> #include <limits> @@ -21,7 +21,7 @@ #include "device/bluetooth/test/bluetooth_test.h" #include "device/fido/ble/fido_ble_frames.h" #include "device/fido/ble/mock_fido_ble_connection.h" -#include "device/fido/fido_cable_device.h" +#include "device/fido/cable/fido_cable_device.h" #include "device/fido/fido_constants.h" #include "device/fido/fido_parsing_utils.h" #include "device/fido/test_callback_receiver.h"
diff --git a/device/fido/ctap_get_assertion_request.h b/device/fido/ctap_get_assertion_request.h index c92ae9f5..beda6ca 100644 --- a/device/fido/ctap_get_assertion_request.h +++ b/device/fido/ctap_get_assertion_request.h
@@ -14,7 +14,7 @@ #include "base/containers/span.h" #include "base/macros.h" #include "base/optional.h" -#include "device/fido/fido_cable_discovery.h" +#include "device/fido/cable/fido_cable_discovery.h" #include "device/fido/fido_constants.h" #include "device/fido/public_key_credential_descriptor.h"
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc index bc300d8..b1ff520 100644 --- a/device/fido/get_assertion_request_handler.cc +++ b/device/fido/get_assertion_request_handler.cc
@@ -9,8 +9,8 @@ #include "base/bind.h" #include "device/fido/authenticator_get_assertion_response.h" +#include "device/fido/cable/fido_cable_discovery.h" #include "device/fido/fido_authenticator.h" -#include "device/fido/fido_cable_discovery.h" #include "device/fido/get_assertion_task.h" namespace device {
diff --git a/extensions/browser/api/networking_config/networking_config_service.cc b/extensions/browser/api/networking_config/networking_config_service.cc index 4fff9e3..f14ba95 100644 --- a/extensions/browser/api/networking_config/networking_config_service.cc +++ b/extensions/browser/api/networking_config/networking_config_service.cc
@@ -35,6 +35,18 @@ return true; } +std::string LookUpExtensionName(content::BrowserContext* context, + std::string extension_id) { + extensions::ExtensionRegistry* extension_registry = + extensions::ExtensionRegistry::Get(context); + DCHECK(extension_registry); + const extensions::Extension* extension = extension_registry->GetExtensionById( + extension_id, extensions::ExtensionRegistry::ENABLED); + if (extension == nullptr) + return std::string(); + return extension->name(); +} + } // namespace NetworkingConfigService::AuthenticationResult::AuthenticationResult() @@ -97,18 +109,35 @@ // Transform hex_ssid to uppercase. transform(hex_ssid.begin(), hex_ssid.end(), hex_ssid.begin(), toupper); - return hex_ssid_to_extension_id_.insert(make_pair(hex_ssid, extension_id)) - .second; + // If |hex_ssid| is already in the map, i.e. if a hex ssid is already + // registered, this call should fail. TODO(stevenjb): Return an error code so + // that the extension API can respond with a better error. + if (!hex_ssid_to_extension_id_.insert(make_pair(hex_ssid, extension_id)) + .second) { + LOG(ERROR) << "\'" << hex_ssid << "\' is already registered."; + return false; + } + + chromeos::NetworkHandler::Get() + ->network_state_handler() + ->SetCaptivePortalProviderForHexSsid( + hex_ssid, extension_id, + LookUpExtensionName(browser_context_, extension_id)); + return true; } void NetworkingConfigService::UnregisterExtension( const std::string& extension_id) { for (auto it = hex_ssid_to_extension_id_.begin(); it != hex_ssid_to_extension_id_.end();) { - if (it->second == extension_id) - hex_ssid_to_extension_id_.erase(it++); - else + if (it->second == extension_id) { + chromeos::NetworkHandler::Get() + ->network_state_handler() + ->SetCaptivePortalProviderForHexSsid(it->first, "", ""); + it = hex_ssid_to_extension_id_.erase(it); + } else { ++it; + } } }
diff --git a/extensions/browser/api/networking_config/networking_config_service_chromeos_unittest.cc b/extensions/browser/api/networking_config/networking_config_service_chromeos_unittest.cc index a04f4f10..cfb4704d 100644 --- a/extensions/browser/api/networking_config/networking_config_service_chromeos_unittest.cc +++ b/extensions/browser/api/networking_config/networking_config_service_chromeos_unittest.cc
@@ -6,6 +6,8 @@ #include <utility> +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/network/network_handler.h" #include "extensions/browser/api_unittest.h" #include "extensions/browser/extension_registry.h" #include "testing/gtest/include/gtest/gtest.h" @@ -45,6 +47,8 @@ void SetUp() override { ApiUnitTest::SetUp(); + chromeos::DBusThreadManager::Initialize(); + chromeos::NetworkHandler::Initialize(); extension_registry_ = std::unique_ptr<ExtensionRegistry>( new ExtensionRegistry(browser_context())); std::unique_ptr<MockEventDelegate> mock_event_delegate = @@ -56,6 +60,12 @@ DCHECK(service_); } + void TearDown() override { + chromeos::NetworkHandler::Shutdown(); + chromeos::DBusThreadManager::Shutdown(); + ApiUnitTest::TearDown(); + } + protected: std::unique_ptr<ExtensionRegistry> extension_registry_; std::unique_ptr<NetworkingConfigService> service_;
diff --git a/extensions/renderer/activity_log_converter_strategy.cc b/extensions/renderer/activity_log_converter_strategy.cc index b6c07472..1663d15 100644 --- a/extensions/renderer/activity_log_converter_strategy.cc +++ b/extensions/renderer/activity_log_converter_strategy.cc
@@ -24,19 +24,23 @@ isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); v8::Local<v8::String> name = v8::String::NewFromUtf8(isolate, "["); if (object->IsFunction()) { - name = - v8::String::Concat(name, v8::String::NewFromUtf8(isolate, "Function")); + name = v8::String::Concat(isolate, name, + v8::String::NewFromUtf8(isolate, "Function")); v8::Local<v8::Value> fname = v8::Local<v8::Function>::Cast(object)->GetName(); if (fname->IsString() && v8::Local<v8::String>::Cast(fname)->Length()) { - name = v8::String::Concat(name, v8::String::NewFromUtf8(isolate, " ")); - name = v8::String::Concat(name, v8::Local<v8::String>::Cast(fname)); - name = v8::String::Concat(name, v8::String::NewFromUtf8(isolate, "()")); + name = v8::String::Concat(isolate, name, + v8::String::NewFromUtf8(isolate, " ")); + name = + v8::String::Concat(isolate, name, v8::Local<v8::String>::Cast(fname)); + name = v8::String::Concat(isolate, name, + v8::String::NewFromUtf8(isolate, "()")); } } else { - name = v8::String::Concat(name, object->GetConstructorName()); + name = v8::String::Concat(isolate, name, object->GetConstructorName()); } - name = v8::String::Concat(name, v8::String::NewFromUtf8(isolate, "]")); + name = + v8::String::Concat(isolate, name, v8::String::NewFromUtf8(isolate, "]")); if (try_catch.HasCaught()) { return std::unique_ptr<base::Value>(
diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc index a83c07e..a30a806 100644 --- a/extensions/renderer/module_system.cc +++ b/extensions/renderer/module_system.cc
@@ -109,9 +109,9 @@ v8::Local<v8::Object> obj = args.This(); CHECK_EQ(2, args.Length()); CHECK(args[0]->IsString()); - v8::Maybe<bool> result = - obj->DefineOwnProperty(args.GetIsolate()->GetCurrentContext(), - args[0]->ToString(), args[1], v8::ReadOnly); + v8::Maybe<bool> result = obj->DefineOwnProperty( + args.GetIsolate()->GetCurrentContext(), + args[0]->ToString(args.GetIsolate()), args[1], v8::ReadOnly); if (!result.FromMaybe(false)) LOG(ERROR) << "Failed to set private property on the export."; } @@ -656,8 +656,8 @@ "$JSON, $Object, $RegExp, $String, $Error) {" "'use strict';"); v8::Local<v8::String> right = ToV8StringUnsafe(GetIsolate(), "\n})"); - return handle_scope.Escape(v8::Local<v8::String>( - v8::String::Concat(left, v8::String::Concat(source, right)))); + return handle_scope.Escape(v8::Local<v8::String>(v8::String::Concat( + GetIsolate(), left, v8::String::Concat(GetIsolate(), source, right)))); } void ModuleSystem::Private(const v8::FunctionCallbackInfo<v8::Value>& args) {
diff --git a/extensions/renderer/safe_builtins.cc b/extensions/renderer/safe_builtins.cc index 24514d4..eac8522 100644 --- a/extensions/renderer/safe_builtins.cc +++ b/extensions/renderer/safe_builtins.cc
@@ -182,7 +182,8 @@ if (info[1]->IsObject()) { recv = v8::Local<v8::Object>::Cast(info[1]); } else if (info[1]->IsString()) { - recv = v8::StringObject::New(v8::Local<v8::String>::Cast(info[1])) + recv = v8::StringObject::New(info.GetIsolate(), + v8::Local<v8::String>::Cast(info[1])) .As<v8::Object>(); } else { info.GetIsolate()->ThrowException(
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc index ff759b0..2616ca5f 100644 --- a/extensions/renderer/script_context.cc +++ b/extensions/renderer/script_context.cc
@@ -428,7 +428,7 @@ } std::string result; for (int i = 0; i < stack_trace->GetFrameCount(); ++i) { - v8::Local<v8::StackFrame> frame = stack_trace->GetFrame(i); + v8::Local<v8::StackFrame> frame = stack_trace->GetFrame(isolate(), i); CHECK(!frame.IsEmpty()); result += base::StringPrintf( "\n at %s (%s:%d:%d)",
diff --git a/gpu/command_buffer/service/gr_cache_controller.cc b/gpu/command_buffer/service/gr_cache_controller.cc index 7708c6e..61717d8 100644 --- a/gpu/command_buffer/service/gr_cache_controller.cc +++ b/gpu/command_buffer/service/gr_cache_controller.cc
@@ -47,8 +47,7 @@ } context_state_->context->MakeCurrent(context_state_->surface.get()); - context_state_->gr_context->purgeUnlockedResources( - false /* scratchResourcesOnly */); + context_state_->gr_context->freeGpuResources(); } } // namespace raster
diff --git a/headless/BUILD.gn b/headless/BUILD.gn index 7070fd4..ad0ee65 100644 --- a/headless/BUILD.gn +++ b/headless/BUILD.gn
@@ -930,6 +930,10 @@ if (is_win) { deps += [ "//build/win:default_exe_manifest" ] } + + if (is_mac) { + deps += [ "//sandbox/mac:seatbelt" ] + } } process_version("version_header") {
diff --git a/headless/app/DEPS b/headless/app/DEPS index a3c5a9c..7646185 100644 --- a/headless/app/DEPS +++ b/headless/app/DEPS
@@ -1,5 +1,6 @@ include_rules = { "+cc/base/switches.h", "+components/viz/common/switches.h", + "+sandbox/mac", }
diff --git a/headless/app/headless_shell_main.cc b/headless/app/headless_shell_main.cc index 5f63fcb..b8963e2 100644 --- a/headless/app/headless_shell_main.cc +++ b/headless/app/headless_shell_main.cc
@@ -8,6 +8,9 @@ #if defined(OS_WIN) #include "content/public/app/sandbox_helper_win.h" #include "sandbox/win/src/sandbox_types.h" +#elif defined(OS_MACOSX) +#include "base/logging.h" +#include "sandbox/mac/seatbelt_exec.h" #endif int main(int argc, const char** argv) { @@ -16,6 +19,15 @@ content::InitializeSandboxInfo(&sandbox_info); return headless::HeadlessShellMain(0, &sandbox_info); #else +#if defined(OS_MACOSX) + sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt = + sandbox::SeatbeltExecServer::CreateFromArguments( + argv[0], argc, const_cast<char**>(argv)); + if (seatbelt.sandbox_required) { + CHECK(seatbelt.server->InitializeSandbox()); + } +#endif // defined(OS_MACOSX) + return headless::HeadlessShellMain(argc, argv); #endif // defined(OS_WIN) }
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg index 195acfa..65158e3 100644 --- a/infra/config/global/luci-milo.cfg +++ b/infra/config/global/luci-milo.cfg
@@ -3456,6 +3456,18 @@ refs: "refs/heads/master" manifest_name: "REVISION" builders { + name: "buildbot/chromium.webrtc/Android Builder" + name: "buildbucket/luci.webrtc.ci/Android Builder" + category: "android" + short_name: "bld" + } + builders { + name: "buildbot/chromium.webrtc/Android Tester" + name: "buildbucket/luci.webrtc.ci/Android Tester" + category: "android" + short_name: "tst" + } + builders { name: "buildbot/chromium.webrtc/Linux Builder" name: "buildbucket/luci.webrtc.ci/Linux Builder" category: "linux"
diff --git a/ios/chrome/browser/metrics/external_url_tab_usage_recorder_egtest.mm b/ios/chrome/browser/metrics/external_url_tab_usage_recorder_egtest.mm index 6194416d..a24d7f0 100644 --- a/ios/chrome/browser/metrics/external_url_tab_usage_recorder_egtest.mm +++ b/ios/chrome/browser/metrics/external_url_tab_usage_recorder_egtest.mm
@@ -29,8 +29,7 @@ @implementation ExternalURLTabUsageRecorderTestCase -// TODO(crbug.com/847948): This test is faling on devices. -// TODO(crbug.com/852341): This test is faling on simulators. +// TODO(crbug.com/852341): This test is failing on devices and simulators. // Verify correct recording of metrics when the reloading of an evicted tab // fails. - (void)DISABLED_testEvictedTabReloadFailure {
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn index ecb64d3a..61423cf 100644 --- a/ios/chrome/browser/passwords/BUILD.gn +++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -73,7 +73,6 @@ "//ios/chrome/app/strings", "//ios/chrome/app/theme", "//ios/chrome/browser", - "//ios/chrome/browser/autofill", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/infobars", "//ios/chrome/browser/signin",
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm index 4a63231..d534ef2 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -13,7 +13,9 @@ #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h" +#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h" +#include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h" #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/browser_sync/browser_sync_switches.h" @@ -350,6 +352,18 @@ web_data_service_.get()) ->change_processor() ->GetControllerDelegateOnUIThread(); + case syncer::AUTOFILL_WALLET_DATA: { + return autofill::AutofillWalletSyncBridge::FromWebDataService( + web_data_service_.get()) + ->change_processor() + ->GetControllerDelegateOnUIThread(); + } + case syncer::AUTOFILL_WALLET_METADATA: { + return autofill::AutofillWalletMetadataSyncBridge::FromWebDataService( + web_data_service_.get()) + ->change_processor() + ->GetControllerDelegateOnUIThread(); + } case syncer::TYPED_URLS: { history::HistoryService* history = ios::HistoryServiceFactory::GetForBrowserState(
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h b/ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h index 7c4ee4f..a796ed3 100644 --- a/ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h +++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h
@@ -16,11 +16,11 @@ // The font size and color to use for detail text that is on the trailing edge // of the top line. -const int kUIKitDetailTextColor = 0x8E8E93; +const int kUIKitDetailTextColor = 0x767676; const CGFloat kUIKitDetailFontSize = 17; // The font size and color to use for detail text that is on its own line. -const int kUIKitMultilineDetailTextColor = 0x8E8E93; +const int kUIKitMultilineDetailTextColor = 0x767676; const CGFloat kUIKitMultilineDetailFontSize = 12; // The font size and color to use for footer text in UIKit-style cells.
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm index 6dd085d..52155e6 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
@@ -122,7 +122,7 @@ _faviconView.font = [[MDCTypography fontLoader] mediumFontOfSize:10]; if (IsUIRefreshPhase1Enabled()) { _additionalInformationLabel.textColor = - [UIColor colorWithWhite:0 alpha:0.4]; + [UIColor colorWithWhite:0 alpha:0.54]; } else { _additionalInformationLabel.textColor = [[MDCPalette greyPalette] tint700];
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm index 8d30ced..7e62bfa9 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm
@@ -13,4 +13,4 @@ const NSInteger kLabelNumLines = 2; const CGFloat kSpaceIconTitle = 10; const CGSize kCellSize = {73, 100}; -const CGFloat kTitleAlpha = 0.41; +const CGFloat kTitleAlpha = 0.54;
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.mm b/ios/chrome/browser/ui/history/history_table_view_controller.mm index 627b9bde..7bf194f 100644 --- a/ios/chrome/browser/ui/history/history_table_view_controller.mm +++ b/ios/chrome/browser/ui/history/history_table_view_controller.mm
@@ -62,6 +62,8 @@ const int kMaxFetchCount = 100; // Separation space between sections. const CGFloat kSeparationSpaceBetweenSections = 9; +// The Alpha value used by the SearchBar when disabled. +const CGFloat kAlphaForDisabledSearchBar = 0.5; } // namespace @interface HistoryTableViewController ()<HistoryEntriesStatusItemDelegate, @@ -848,6 +850,8 @@ self.clearBrowsingDataButton, spaceButton, self.editButton ] animated:animated]; + [self.searchController.searchBar setUserInteractionEnabled:YES]; + self.searchController.searchBar.alpha = 1.0; [self updateToolbarButtons]; } @@ -860,6 +864,8 @@ action:nil]; [self setToolbarItems:@[ self.deleteButton, spaceButton, self.cancelButton ] animated:animated]; + [self.searchController.searchBar setUserInteractionEnabled:NO]; + self.searchController.searchBar.alpha = kAlphaForDisabledSearchBar; [self updateToolbarButtons]; }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm index 6658a656..74e7732 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/ui/omnibox/omnibox_coordinator.h" #include "base/logging.h" +#include "base/strings/sys_string_conversions.h" #include "components/omnibox/browser/omnibox_edit_model.h" #include "components/strings/grit/components_strings.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -12,6 +13,7 @@ #import "ios/chrome/browser/ui/location_bar/location_bar_constants.h" #import "ios/chrome/browser/ui/omnibox/omnibox_mediator.h" #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h" +#include "ios/chrome/browser/ui/omnibox/omnibox_util.h" #include "ios/chrome/browser/ui/omnibox/omnibox_view_controller.h" #include "ios/chrome/browser/ui/omnibox/omnibox_view_ios.h" #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h" @@ -54,6 +56,19 @@ self.viewController = [[OmniboxViewController alloc] initWithIncognito:isIncognito]; + std::string defaultLeadingImageName = GetResourceNameForAutocompleteMatchType( + AutocompleteMatchType::URL_WHAT_YOU_TYPED, /* is_starred */ false); + UIImage* defaultLeadingImage = + [[UIImage imageNamed:base::SysUTF8ToNSString(defaultLeadingImageName)] + imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.viewController.defaultLeadingImage = defaultLeadingImage; + std::string defaultEmptyOmniboxLeadingImageName = + GetResourceNameForAutocompleteMatchType( + AutocompleteMatchType::SEARCH_SUGGEST, /* is_starred */ false); + UIImage* defaultEmptyOmniboxLeadingImage = [[UIImage + imageNamed:base::SysUTF8ToNSString(defaultEmptyOmniboxLeadingImageName)] + imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.viewController.emptyTextLeadingImage = defaultEmptyOmniboxLeadingImage; self.viewController.dispatcher = static_cast<id<LoadQueryCommands, OmniboxFocuser>>(self.dispatcher);
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h index c6936d22..8aeaa26 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h +++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.h
@@ -21,6 +21,13 @@ // The textfield used by this view controller. @property(nonatomic, readonly, strong) OmniboxTextFieldIOS* textField; +// The default leading image to be used on omnibox focus before this is updated +// via OmniboxConsumer protocol. +@property(nonatomic, strong) UIImage* defaultLeadingImage; + +// The default leading image to be used whenever the omnibox text is empty. +@property(nonatomic, strong) UIImage* emptyTextLeadingImage; + // Designated initializer. - (instancetype)initWithIncognito:(BOOL)isIncognito;
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm index 8633c9c..a5a20a9 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -37,6 +37,8 @@ @implementation OmniboxViewController @synthesize incognito = _incognito; @synthesize dispatcher = _dispatcher; +@synthesize defaultLeadingImage = _defaultLeadingImage; +@synthesize emptyTextLeadingImage = _emptyTextLeadingImage; @dynamic view; - (instancetype)initWithIncognito:(BOOL)isIncognito { @@ -92,6 +94,11 @@ selector:@selector(textFieldDidBeginEditing) name:UITextFieldTextDidBeginEditingNotification object:self.textField]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(textFieldDidChange) + name:UITextFieldTextDidChangeNotification + object:self.textField]; } - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { @@ -135,6 +142,16 @@ - (void)textFieldDidBeginEditing { // Update the clear button state. [self updateClearButtonVisibility]; + [self.view setLeadingImage:self.textField.text.length + ? self.defaultLeadingImage + : self.emptyTextLeadingImage]; +} + +- (void)textFieldDidChange { + // If the text is empty, update the leading image. + if (self.textField.text.length == 0) { + [self.view setLeadingImage:self.emptyTextLeadingImage]; + } } #pragma mark clear button @@ -185,6 +202,7 @@ // Calling setText: does not trigger UIControlEventEditingChanged, so update // the clear button visibility manually. [self updateClearButtonVisibility]; + [self textFieldDidChange]; } }
diff --git a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm index 5e1d5218..54d9c98 100644 --- a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
@@ -326,12 +326,13 @@ CollectionViewItem* item = [self.collectionViewModel itemAtIndexPath:indexPath]; if (item.type == ItemTypeMessage) { - CardMultilineCell* messageCell = - base::mac::ObjCCastStrict<CardMultilineCell>(cell); - if (experimental_flags::IsSettingsUIRebootEnabled()) { - messageCell.textLabel.font = - [UIFont boldSystemFontOfSize:kUIKitMainFontSize]; - } else { + // Changing the font weight may reflow the text onto a different number of + // lines, but the collection view doesn't know that it needs to layout the + // cell again. Sidestep this bug by leaving the font at a normal weight + // under UIRefresh. + if (!experimental_flags::IsSettingsUIRebootEnabled()) { + CardMultilineCell* messageCell = + base::mac::ObjCCastStrict<CardMultilineCell>(cell); messageCell.textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14]; }
diff --git a/ios/third_party/firebase/.gitignore b/ios/third_party/firebase/.gitignore new file mode 100644 index 0000000..0354386 --- /dev/null +++ b/ios/third_party/firebase/.gitignore
@@ -0,0 +1,3 @@ +/Analytics +/NOTICES +/README.md
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 4e48ec8..2abad79 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -4987,10 +4987,6 @@ NSURLCredential*))completionHandler { [self didReceiveWebViewNavigationDelegateCallback]; - // This callback should never be triggered for placeholder navigations. - DCHECK(!(web::GetWebClient()->IsSlimNavigationManagerEnabled() && - IsPlaceholderUrl(net::GURLWithNSURL(webView.URL)))); - NSString* authMethod = challenge.protectionSpace.authenticationMethod; if ([authMethod isEqual:NSURLAuthenticationMethodHTTPBasic] || [authMethod isEqual:NSURLAuthenticationMethodNTLM] ||
diff --git a/net/third_party/spdy/core/priority_write_scheduler.h b/net/third_party/spdy/core/priority_write_scheduler.h index ba75f3ac..7738c7a 100644 --- a/net/third_party/spdy/core/priority_write_scheduler.h +++ b/net/third_party/spdy/core/priority_write_scheduler.h
@@ -250,8 +250,7 @@ // Returns the number of ready streams. size_t NumReadyStreams() const override { return num_ready_streams_; } - // This function is used for debugging and test only. Returns true if a stream - // is ready. + // Returns true if a stream is ready. bool IsStreamReady(StreamIdType stream_id) const { auto it = stream_infos_.find(stream_id); if (it == stream_infos_.end()) {
diff --git a/rlz/lib/rlz_lib.cc b/rlz/lib/rlz_lib.cc index d61189ad..493ae90 100644 --- a/rlz/lib/rlz_lib.cc +++ b/rlz/lib/rlz_lib.cc
@@ -395,6 +395,18 @@ const char* product_brand, const char* product_id, const char* product_lang, + bool exclude_machine_id) { + return SendFinancialPing(product, access_points, product_signature, + product_brand, product_id, product_lang, + exclude_machine_id, false); +} + +bool SendFinancialPing(Product product, + const AccessPoint* access_points, + const char* product_signature, + const char* product_brand, + const char* product_id, + const char* product_lang, bool exclude_machine_id, const bool skip_time_check) { // Create the financial ping request. To support ChromeOS retries, the
diff --git a/rlz/lib/rlz_lib.h b/rlz/lib/rlz_lib.h index 9bc942f..886bd0c 100644 --- a/rlz/lib/rlz_lib.h +++ b/rlz/lib/rlz_lib.h
@@ -194,7 +194,6 @@ // product_lang : The language for the product (used to determine cohort). // exclude_machine_id : Whether the Machine ID should be explicitly excluded // based on the products privacy policy. -// skip_time_check : Whether the timing check. // // Returns true on successful ping and response, false otherwise. // Access: HKCU write. @@ -204,6 +203,16 @@ const char* product_brand, const char* product_id, const char* product_lang, + bool exclude_machine_id); + +// An alternate implementations of SendFinancialPing with the same behavior, +// except the caller can optionally choose to skip the timing check. +bool RLZ_LIB_API SendFinancialPing(Product product, + const AccessPoint* access_points, + const char* product_signature, + const char* product_brand, + const char* product_id, + const char* product_lang, bool exclude_machine_id, const bool skip_time_check);
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc index 285f46b..4d3c7166 100644 --- a/services/identity/public/cpp/identity_manager.cc +++ b/services/identity/public/cpp/identity_manager.cc
@@ -305,21 +305,24 @@ account_info.gaia = kSupervisedUserPseudoGaiaID; } - // Insert the account into |accounts_with_refresh_tokens_|. - auto insertion_result = accounts_with_refresh_tokens_.emplace( - account_id, std::move(account_info)); - - // The account might have already been present (e.g., this method can fire on + // The account might have already been present (e.g., this method can fire on // updating an invalid token to a valid one or vice versa); in this case we // sanity-check that the cached account info has the expected values. - if (!insertion_result.second) { - AccountInfo cached_account_info = insertion_result.first->second; - DCHECK_EQ(account_info.gaia, cached_account_info.gaia); - DCHECK_EQ(account_info.email, cached_account_info.email); + auto iterator = accounts_with_refresh_tokens_.find(account_id); + if (iterator != accounts_with_refresh_tokens_.end()) { + DCHECK_EQ(account_info.gaia, iterator->second.gaia); + DCHECK(gaia::AreEmailsSame(account_info.email, iterator->second.email)); + } else { + auto insertion_result = accounts_with_refresh_tokens_.emplace( + account_id, std::move(account_info)); + DCHECK(insertion_result.second); + iterator = insertion_result.first; } + // Use iterator instead of account_info as it may have been moved, thus is + // invalid to use. for (auto& observer : observer_list_) { - observer.OnRefreshTokenUpdatedForAccount(account_info, is_valid); + observer.OnRefreshTokenUpdatedForAccount(iterator->second, is_valid); } }
diff --git a/testing/buildbot/filters/mash.browser_tests.filter b/testing/buildbot/filters/mash.browser_tests.filter index 184cd337..c4293c7 100644 --- a/testing/buildbot/filters/mash.browser_tests.filter +++ b/testing/buildbot/filters/mash.browser_tests.filter
@@ -44,6 +44,9 @@ -HostedAppNonClientFrameViewAshTest.* -HomeLauncherBrowserNonClientFrameViewAshTest.* +BrowserNonClientFrameViewAshTest.NonClientHitTest* +BrowserNonClientFrameViewAshTest.AvatarMenuButtonHitTest* + # Fix immersive fullscreen mode in mash. https://crbug.com/844748. -ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInAppImmersiveMode* -ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInBrowserImmersiveMode* @@ -177,8 +180,10 @@ -MultiAuthEnrollmentScreenTest.* -ProvisionedEnrollmentScreenTest.* -# VPN item not in system tray. --NetworkingConfigDelegateChromeosTest.* +# Ash currently uses its own NetworkHandler instance so the +# captive_portal_provider_ member of networkState is not set correctly. +# https://crbug.com/862420 +-NetworkingConfigChromeosTest.SystemTrayItem # Timeout device_event_log_impl.cc(156) Network: network_portal_detector_impl.cc:486 Portal detection timeout: name= id= -NetworkingConfigTest.*
diff --git a/testing/buildbot/filters/viz.content_browsertests.filter b/testing/buildbot/filters/viz.content_browsertests.filter index bf0ea54..c961980b 100644 --- a/testing/buildbot/filters/viz.content_browsertests.filter +++ b/testing/buildbot/filters/viz.content_browsertests.filter
@@ -1,7 +1 @@ ### Mac -# BrowserSideFlingBrowserTest timing out https://crbug.com/842325 --BrowserSideFlingBrowserTest.AutoscrollFling --BrowserSideFlingBrowserTest.TouchpadFling --BrowserSideFlingBrowserTest.TouchscreenFling --SitePerProcessBrowserTest.TouchpadGestureFlingStart --SitePerProcessBrowserTest.TouchscreenGestureFlingStart
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG index 341eee0f..6d37ab4 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -723,8 +723,6 @@ crbug.com/591099 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Timeout ] crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Pass ] crbug.com/591099 storage/indexeddb/objectstore-keycursor.html [ Timeout ] -crbug.com/591099 svg/as-border-image/svg-as-border-image-2.html [ Failure ] -crbug.com/591099 svg/as-border-image/svg-as-border-image.html [ Failure ] crbug.com/591099 svg/custom/object-sizing-no-width-height.xhtml [ Failure ] crbug.com/591099 svg/filters/feTurbulence-bad-seeds.html [ Failure ] crbug.com/591099 svg/in-html/sizing/svg-inline.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 206b772..76c80984 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2642,7 +2642,7 @@ crbug.com/828506 [ Linux Win ] virtual/mouseevent_fractional/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Pass Failure ] crbug.com/828506 [ Linux Win ] virtual/scroll_customization/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Pass Failure ] crbug.com/828506 [ Linux Win ] virtual/user-activation-v2/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Pass Failure ] - +crbug.com/828506 [ Linux Win ] virtual/paint-touchaction-rects/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Failure Pass ] # Failure messages are unstable so we cannot create baselines. crbug.com/832071 external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] @@ -4670,6 +4670,7 @@ ### virtual/gpu/fast/canvas/ blending layout tests timeout crbug.com/866850 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blend-image.html [ Pass Timeout ] +crbug.com/866850 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-color-over-image.html [ Pass Timeout ] crbug.com/866850 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-gradient-over-image.html [ Pass Timeout ] crbug.com/866850 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-image-over-image.html [ Pass Timeout ] crbug.com/866850 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-color.html [ Pass Timeout ] @@ -4682,4 +4683,3 @@ crbug.com/866965 [ Linux ] virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Timeout Pass ] crbug.com/866965 [ Linux ] virtual/outofblink-cors/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Timeout Pass ] crbug.com/866965 [ Linux ] virtual/service-worker-servicification/external/wpt/service-workers/service-worker/interfaces-sw.https.html [ Timeout Pass ] -crbug.com/867181 [ Win10 ] virtual/paint-touchaction-rects/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.png b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.png index 0ec8463..b37b180 100644 --- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.png +++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt index 4fb10f76..e6cb740 100644 --- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
@@ -29,11 +29,13 @@ }, { "name": "Scrolling Layer", + "position": [15, 0], "bounds": [385, 385], "drawsContent": false }, { "name": "Scrolling Contents Layer", + "position": [15, 0], "bounds": [1000, 1000], "backgroundColor": "#FF0000", "transform": 1 @@ -52,19 +54,18 @@ }, { "name": "Horizontal Scrollbar Layer", - "position": [0, 385], + "position": [15, 385], "bounds": [385, 15], "drawsContent": false }, { "name": "Vertical Scrollbar Layer", - "position": [385, 0], "bounds": [15, 385], "drawsContent": false }, { "name": "Scroll Corner Layer", - "position": [385, 385], + "position": [0, 385], "bounds": [15, 15] } ], @@ -86,7 +87,7 @@ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], - [665, 50, 0, 1] + [680, 50, 0, 1] ] } ]
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.png b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.png index f3ec1ff5..d034ccea 100644 --- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.png +++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt index 5f9aae9e..bfb7bb0 100644 --- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt +++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt
@@ -29,11 +29,13 @@ }, { "name": "Scrolling Layer", + "position": [15, 0], "bounds": [385, 385], "drawsContent": false }, { "name": "Scrolling Contents Layer", + "position": [15, 0], "bounds": [1000, 1000], "backgroundColor": "#FF0000", "transform": 1 @@ -52,19 +54,18 @@ }, { "name": "Horizontal Scrollbar Layer", - "position": [0, 385], + "position": [15, 385], "bounds": [385, 15], "drawsContent": false }, { "name": "Vertical Scrollbar Layer", - "position": [385, 0], "bounds": [15, 385], "drawsContent": false }, { "name": "Scroll Corner Layer", - "position": [385, 385], + "position": [0, 385], "bounds": [15, 15] } ], @@ -86,7 +87,7 @@ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], - [51, 50, 0, 1] + [66, 50, 0, 1] ] } ]
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.png b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.png index 0ec8463..b37b180 100644 --- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.png +++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt index 17e7b97..2c2c0e57 100644 --- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
@@ -29,18 +29,20 @@ }, { "name": "Scrolling Layer", + "position": [15, 0], "bounds": [385, 385], "drawsContent": false }, { "name": "Scrolling Contents Layer", + "position": [15, 0], "bounds": [1000, 1000], "backgroundColor": "#FF0000", "transform": 1 }, { "name": "LayoutBlockFlow (positioned) DIV class='positioned indicator'", - "position": [665, 50], + "position": [680, 50], "bounds": [100, 100], "contentsOpaque": true, "backgroundColor": "#FF0000", @@ -60,19 +62,18 @@ }, { "name": "Horizontal Scrollbar Layer", - "position": [0, 385], + "position": [15, 385], "bounds": [385, 15], "drawsContent": false }, { "name": "Vertical Scrollbar Layer", - "position": [385, 0], "bounds": [15, 385], "drawsContent": false }, { "name": "Scroll Corner Layer", - "position": [385, 385], + "position": [0, 385], "bounds": [15, 15] } ], @@ -94,7 +95,7 @@ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], - [665, 50, 0, 1] + [680, 50, 0, 1] ] } ]
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.png b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.png index f3ec1ff5..d034ccea 100644 --- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.png +++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt index 17e7b97..2c2c0e57 100644 --- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt +++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt
@@ -29,18 +29,20 @@ }, { "name": "Scrolling Layer", + "position": [15, 0], "bounds": [385, 385], "drawsContent": false }, { "name": "Scrolling Contents Layer", + "position": [15, 0], "bounds": [1000, 1000], "backgroundColor": "#FF0000", "transform": 1 }, { "name": "LayoutBlockFlow (positioned) DIV class='positioned indicator'", - "position": [665, 50], + "position": [680, 50], "bounds": [100, 100], "contentsOpaque": true, "backgroundColor": "#FF0000", @@ -60,19 +62,18 @@ }, { "name": "Horizontal Scrollbar Layer", - "position": [0, 385], + "position": [15, 385], "bounds": [385, 15], "drawsContent": false }, { "name": "Vertical Scrollbar Layer", - "position": [385, 0], "bounds": [15, 385], "drawsContent": false }, { "name": "Scroll Corner Layer", - "position": [385, 385], + "position": [0, 385], "bounds": [15, 15] } ], @@ -94,7 +95,7 @@ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], - [665, 50, 0, 1] + [680, 50, 0, 1] ] } ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerlock/mouse_buttons_back_forward-manual.html b/third_party/WebKit/LayoutTests/external/wpt/pointerlock/mouse_buttons_back_forward-manual.html new file mode 100644 index 0000000..06e0a5da --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/pointerlock/mouse_buttons_back_forward-manual.html
@@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <title>Mouse Button Back/Forward</title> + <link rel="author" title="Google" href="http://www.google.com/" /> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script> + var testMouseUp = async_test('Tests that when pointer is locked, the mouseup is preventable.'); + var received_back = false; + var received_forward = false; + window.addEventListener('mouseup', function(e) { + if (e.button == 0) { + document.body.requestPointerLock(); + } else if (e.button == 3) { + received_back = true; + e.preventDefault(); + } else if (e.button == 4) { + received_forward = true; + e.preventDefault(); + } + if (document.pointerLockElement && received_back && received_forward) { + testMouseUp.done(); + document.exitPointerLock(); + } + }); + + </script> + + </head> + <body id="target"> + <h4>Test Description: Tests that the mouseup event is prevented. + <ol> + <li>Click the left mouse button to lock pointer</li> + <li>Click the back mouse button</li> + <li>Click the back mouse forward</li> + </ol> + </h4> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt_automation/pointerlock/mouse_buttons_back_forward-manual-automation.js b/third_party/WebKit/LayoutTests/external/wpt_automation/pointerlock/mouse_buttons_back_forward-manual-automation.js new file mode 100644 index 0000000..d259f6db7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt_automation/pointerlock/mouse_buttons_back_forward-manual-automation.js
@@ -0,0 +1,8 @@ +importAutomationScript('/pointerevents/pointerevent_common_input.js'); +function inject_input() { + return mouseClickInTarget('#target', undefined, "left").then(function() { + return mouseClickInTarget('#target', undefined, "back").then(function() { + return mouseClickInTarget('#target', undefined, "forward"); + }); + }); +}
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-overlap.html b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-overlap.html new file mode 100644 index 0000000..5fa3516 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-tap-frame-overlap.html
@@ -0,0 +1,60 @@ +<!DOCTYPE html> +<html> +<script src="../../../../resources/testharness.js"></script> +<script src="../../../../resources/testharnessreport.js"></script> +<script src="../../../../resources/gesture-util.js"></script> +<style type="text/css"> +body { + margin: 0; +} +#box1{ + position: fixed; + bottom: 96px; + left: 0; + right: 0; + height: 100px; + background-color: #1976D2; + z-index: 101; +} +#box2 { + position: fixed; + bottom: 0; + left: 0; + right: 0; + height: 100px; + background-color: #03A9F4; + z-index: 100; +} +</style> +<body> +<div id="box1"></div> +<div id="box2"></div> + +<script> +var outerCount = 0; +var innerCount = 0; +document.addEventListener("click", function(event) { + outerCount++; +}) +function createIframe() { + var fr = document.createElement('iframe'); + fr.frameborder="0"; + fr.style.height = (window.innerHeight - 50) + "px"; + fr.style.width = "100%"; + document.body.appendChild(fr); + fr.contentDocument.body.innerHTML = '<div id="target" style="margin: 0px; width: 100%; height: ' + window.innerHeight + 'px; background-color:red"></div>'; + fr.contentDocument.getElementById("target").addEventListener("click", function(event) { + innerCount++; + }) +} + +promise_test (async() => { + createIframe(); + await touchTapOn(innerWidth / 2, window.innerHeight - 100); + assert_equals(innerCount, 0); + assert_equals(outerCount, 1); +}) + +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash-expected.txt b/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash-expected.txt new file mode 100644 index 0000000..654ddf7f --- /dev/null +++ b/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash-expected.txt
@@ -0,0 +1 @@ +This test passes if it does not crash.
diff --git a/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash.html b/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash.html new file mode 100644 index 0000000..af39c63 --- /dev/null +++ b/third_party/WebKit/LayoutTests/html/marquee/marquee-zero-width-crash.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<title>Test: Positive content-width, zero marquee-width should not crash</title> +<style> +/* Style taken from clusterfuzz reproduction in http://crbug.com/866289 */ +marquee { + display: table-row-group; + padding-left: 100px; +} +</style> +<marquee></marquee> + +<div>This test passes if it does not crash.</div> + +<script> +if (window.testRunner) + testRunner.dumpAsText(); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/update-no-controllee.https-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/update-no-controllee.https-expected.txt deleted file mode 100644 index 3e0ec4b..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/update-no-controllee.https-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL Verify multiple updates from service workers without controllees do not resolve immediately assert_equals: update should not have succeeded expected "failure" but got "success" -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png index 85f6436..e531dd0 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt index cb7001e..8a2e016 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt
@@ -3,37 +3,33 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 - LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)] - LayoutBlockFlow {H2} at (1,20.91) size 368x27 + LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)] + LayoutBlockFlow {H2} at (1,20.91) size 364x27 LayoutText {#text} at (0,0) size 195x26 text run at (0,0) width 195: "SVG border-image" - LayoutBlockFlow (anonymous) at (1,67.81) size 368x370 + LayoutBlockFlow (anonymous) at (1,67.81) size 364x370 LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,165) size 4x19 text run at (180,165) width 4: " " LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)] - LayoutText {#text} at (364,165) size 4x19 - text run at (364,165) width 4: " " - LayoutBR {BR} at (0,0) size 0x0 + LayoutBR {BR} at (364,180) size 0x0 LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,350) size 4x19 text run at (180,350) width 4: " " LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (370,417) size 4x20 - text run at (370,417) width 4: " " - LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)] - LayoutBlockFlow {H2} at (1,20.91) size 368x27 + LayoutText {#text} at (366,417) size 4x20 + text run at (366,417) width 4: " " + LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)] + LayoutBlockFlow {H2} at (1,20.91) size 364x27 LayoutText {#text} at (0,0) size 197x26 text run at (0,0) width 197: "PNG border-image" - LayoutBlockFlow (anonymous) at (1,67.81) size 368x370 + LayoutBlockFlow (anonymous) at (1,67.81) size 364x370 LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,165) size 4x19 text run at (180,165) width 4: " " LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)] - LayoutText {#text} at (364,165) size 4x19 - text run at (364,165) width 4: " " - LayoutBR {BR} at (0,0) size 0x0 + LayoutBR {BR} at (364,180) size 0x0 LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,350) size 4x19 text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png index 659d31bc..d80f7c8 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt index cb7001e..8a2e016 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt
@@ -3,37 +3,33 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 - LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)] - LayoutBlockFlow {H2} at (1,20.91) size 368x27 + LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)] + LayoutBlockFlow {H2} at (1,20.91) size 364x27 LayoutText {#text} at (0,0) size 195x26 text run at (0,0) width 195: "SVG border-image" - LayoutBlockFlow (anonymous) at (1,67.81) size 368x370 + LayoutBlockFlow (anonymous) at (1,67.81) size 364x370 LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,165) size 4x19 text run at (180,165) width 4: " " LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)] - LayoutText {#text} at (364,165) size 4x19 - text run at (364,165) width 4: " " - LayoutBR {BR} at (0,0) size 0x0 + LayoutBR {BR} at (364,180) size 0x0 LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,350) size 4x19 text run at (180,350) width 4: " " LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (370,417) size 4x20 - text run at (370,417) width 4: " " - LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)] - LayoutBlockFlow {H2} at (1,20.91) size 368x27 + LayoutText {#text} at (366,417) size 4x20 + text run at (366,417) width 4: " " + LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)] + LayoutBlockFlow {H2} at (1,20.91) size 364x27 LayoutText {#text} at (0,0) size 197x26 text run at (0,0) width 197: "PNG border-image" - LayoutBlockFlow (anonymous) at (1,67.81) size 368x370 + LayoutBlockFlow (anonymous) at (1,67.81) size 364x370 LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,165) size 4x19 text run at (180,165) width 4: " " LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)] - LayoutText {#text} at (364,165) size 4x19 - text run at (364,165) width 4: " " - LayoutBR {BR} at (0,0) size 0x0 + LayoutBR {BR} at (364,180) size 0x0 LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,350) size 4x19 text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png index 9c6d810..72538246 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt index 393845f..6088ad2 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt
@@ -3,37 +3,33 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 - LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)] - LayoutBlockFlow {H2} at (1,20.91) size 368x27 + LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)] + LayoutBlockFlow {H2} at (1,20.91) size 364x27 LayoutText {#text} at (0,0) size 193x26 text run at (0,0) width 193: "SVG border-image" - LayoutBlockFlow (anonymous) at (1,67.81) size 368x370 + LayoutBlockFlow (anonymous) at (1,67.81) size 364x370 LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,165) size 4x19 text run at (180,165) width 4: " " LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)] - LayoutText {#text} at (364,165) size 4x19 - text run at (364,165) width 4: " " - LayoutBR {BR} at (0,0) size 0x0 + LayoutBR {BR} at (364,180) size 0x0 LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,350) size 4x19 text run at (180,350) width 4: " " LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (370,417) size 4x20 - text run at (370,417) width 4: " " - LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)] - LayoutBlockFlow {H2} at (1,20.91) size 368x27 + LayoutText {#text} at (366,417) size 4x20 + text run at (366,417) width 4: " " + LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)] + LayoutBlockFlow {H2} at (1,20.91) size 364x27 LayoutText {#text} at (0,0) size 195x26 text run at (0,0) width 195: "PNG border-image" - LayoutBlockFlow (anonymous) at (1,67.81) size 368x370 + LayoutBlockFlow (anonymous) at (1,67.81) size 364x370 LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,165) size 4x19 text run at (180,165) width 4: " " LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)] - LayoutText {#text} at (364,165) size 4x19 - text run at (364,165) width 4: " " - LayoutBR {BR} at (0,0) size 0x0 + LayoutBR {BR} at (364,180) size 0x0 LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,350) size 4x19 text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png index a741647..43c7ca80 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt index 393845f..6088ad2 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt
@@ -3,37 +3,33 @@ layer at (0,0) size 800x600 LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 - LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)] - LayoutBlockFlow {H2} at (1,20.91) size 368x27 + LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)] + LayoutBlockFlow {H2} at (1,20.91) size 364x27 LayoutText {#text} at (0,0) size 193x26 text run at (0,0) width 193: "SVG border-image" - LayoutBlockFlow (anonymous) at (1,67.81) size 368x370 + LayoutBlockFlow (anonymous) at (1,67.81) size 364x370 LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,165) size 4x19 text run at (180,165) width 4: " " LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)] - LayoutText {#text} at (364,165) size 4x19 - text run at (364,165) width 4: " " - LayoutBR {BR} at (0,0) size 0x0 + LayoutBR {BR} at (364,180) size 0x0 LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,350) size 4x19 text run at (180,350) width 4: " " LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (370,417) size 4x20 - text run at (370,417) width 4: " " - LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)] - LayoutBlockFlow {H2} at (1,20.91) size 368x27 + LayoutText {#text} at (366,417) size 4x20 + text run at (366,417) width 4: " " + LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)] + LayoutBlockFlow {H2} at (1,20.91) size 364x27 LayoutText {#text} at (0,0) size 195x26 text run at (0,0) width 195: "PNG border-image" - LayoutBlockFlow (anonymous) at (1,67.81) size 368x370 + LayoutBlockFlow (anonymous) at (1,67.81) size 364x370 LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,165) size 4x19 text run at (180,165) width 4: " " LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)] - LayoutText {#text} at (364,165) size 4x19 - text run at (364,165) width 4: " " - LayoutBR {BR} at (0,0) size 0x0 + LayoutBR {BR} at (364,180) size 0x0 LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)] LayoutText {#text} at (180,350) size 4x19 text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/resources/gesture-util.js b/third_party/WebKit/LayoutTests/resources/gesture-util.js index 7bb73356a..9fae8c4 100644 --- a/third_party/WebKit/LayoutTests/resources/gesture-util.js +++ b/third_party/WebKit/LayoutTests/resources/gesture-util.js
@@ -236,6 +236,21 @@ }); } +function touchTapOn(xPosition, yPosition) { + return new Promise(function(resolve, reject) { + if (window.chrome && chrome.gpuBenchmarking) { + chrome.gpuBenchmarking.pointerActionSequence( [ + {source: 'touch', + actions: [ + { name: 'pointerDown', x: xPosition, y: yPosition }, + { name: 'pointerUp' } + ]}], resolve); + } else { + reject(); + } + }); +} + function approx_equals(actual, expected, epsilon) { return actual >= expected - epsilon && actual <= expected + epsilon; } \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html index 57346e0..a9f2868 100644 --- a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html +++ b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html
@@ -57,8 +57,7 @@ <div class="svg"> <h2>SVG border-image</h2> <div class="rr"></div> - <div class="rs"></div> - <br> + <div class="rs"></div><br> <div class="sr"></div> <div class="ss"></div> </div> @@ -66,8 +65,7 @@ <div class="image"> <h2>PNG border-image</h2> <div class="rr"></div> - <div class="rs"></div> - <br> + <div class="rs"></div><br> <div class="sr"></div> <div class="ss"></div> </div>
diff --git a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html index a9bf8b9f..a3d7aeb 100644 --- a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html +++ b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html
@@ -57,8 +57,7 @@ <div class="svg"> <h2>SVG border-image</h2> <div class="rr"></div> - <div class="rs"></div> - <br> + <div class="rs"></div><br> <div class="sr"></div> <div class="ss"></div> </div> @@ -66,8 +65,7 @@ <div class="image"> <h2>PNG border-image</h2> <div class="rr"></div> - <div class="rs"></div> - <br> + <div class="rs"></div><br> <div class="sr"></div> <div class="ss"></div> </div>
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom index 40516ff..98953f2 100644 --- a/third_party/blink/public/platform/web_feature.mojom +++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1974,6 +1974,7 @@ kV8RTCPeerConnection_AddTransceiver_Method = 2513, kV8RTCRtpTransceiver_Direction_AttributeGetter = 2514, kV8RTCRtpTransceiver_Direction_AttributeSetter = 2515, + kHTMLLinkElementDisabledByParser = 2516, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc index ec89538..d4e554b 100644 --- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc +++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer.cc
@@ -32,6 +32,7 @@ #include "third_party/blink/renderer/core/geometry/dom_rect_read_only.h" #include "third_party/blink/renderer/core/html/canvas/image_data.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h" +#include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h" #include "third_party/blink/renderer/platform/wtf/date_math.h" #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc index a32e43c7..01d2fde1 100644 --- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc +++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
@@ -45,6 +45,7 @@ #include "third_party/blink/renderer/core/messaging/message_port.h" #include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/wtf/date_math.h"
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index bd073cb..29d5b38 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1983,11 +1983,11 @@ "loader/base_fetch_context_test.cc", "loader/document_load_timing_test.cc", "loader/document_loader_test.cc", - "loader/document_threadable_loader_test.cc", "loader/frame_fetch_context_test.cc", "loader/idleness_detector_test.cc", "loader/interactive_detector_test.cc", "loader/link_loader_test.cc", + "loader/long_task_detector_test.cc", "loader/mixed_content_checker_test.cc", "loader/modulescript/module_script_loader_test.cc", "loader/modulescript/module_tree_linker_test.cc",
diff --git a/third_party/blink/renderer/core/clipboard/data_object.cc b/third_party/blink/renderer/core/clipboard/data_object.cc index b81a304..70125b4f 100644 --- a/third_party/blink/renderer/core/clipboard/data_object.cc +++ b/third_party/blink/renderer/core/clipboard/data_object.cc
@@ -36,6 +36,7 @@ #include "third_party/blink/renderer/core/clipboard/clipboard_utilities.h" #include "third_party/blink/renderer/core/clipboard/dragged_isolated_file_system.h" #include "third_party/blink/renderer/core/clipboard/system_clipboard.h" +#include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/paste_mode.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h"
diff --git a/third_party/blink/renderer/core/clipboard/data_object_test.cc b/third_party/blink/renderer/core/clipboard/data_object_test.cc index a28fa65..64f75a7 100644 --- a/third_party/blink/renderer/core/clipboard/data_object_test.cc +++ b/third_party/blink/renderer/core/clipboard/data_object_test.cc
@@ -6,6 +6,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/clipboard/data_object_item.h" +#include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" namespace blink {
diff --git a/third_party/blink/renderer/core/editing/editing_utilities.cc b/third_party/blink/renderer/core/editing/editing_utilities.cc index 85114d2..45b02042 100644 --- a/third_party/blink/renderer/core/editing/editing_utilities.cc +++ b/third_party/blink/renderer/core/editing/editing_utilities.cc
@@ -72,6 +72,7 @@ #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_table_cell.h" #include "third_party/blink/renderer/core/svg/svg_image_element.h" +#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" @@ -1701,7 +1702,7 @@ if (layout_object->IsCanvas()) { return ToHTMLCanvasElement(const_cast<Node&>(node)) - .CopiedImage(kFrontBuffer, kPreferNoAcceleration); + .Snapshot(kFrontBuffer, kPreferNoAcceleration); } if (!layout_object->IsImage())
diff --git a/third_party/blink/renderer/core/editing/finder/text_finder.cc b/third_party/blink/renderer/core/editing/finder/text_finder.cc index 3f01432..9eb03b4 100644 --- a/third_party/blink/renderer/core/editing/finder/text_finder.cc +++ b/third_party/blink/renderer/core/editing/finder/text_finder.cc
@@ -443,7 +443,7 @@ const double kMaxScopingDuration = 0.1; // seconds int match_count = 0; - bool timed_out = false; + bool full_range_searched = false; double start_time = CurrentTime(); PositionInFlatTree next_scoping_start; do { @@ -457,6 +457,7 @@ search_text, options.match_case ? 0 : kCaseInsensitive); if (result.IsCollapsed()) { // Not found. + full_range_searched = true; break; } Range* result_range = Range::Create( @@ -516,8 +517,7 @@ search_start = result.EndPosition(); next_scoping_start = search_start; - timed_out = (CurrentTime() - start_time) >= kMaxScopingDuration; - } while (!timed_out); + } while (CurrentTime() - start_time < kMaxScopingDuration); if (next_scoping_start.IsNotNull()) { resume_scoping_from_range_ = @@ -540,7 +540,7 @@ IncreaseMatchCount(identifier, match_count); } - if (timed_out) { + if (!full_range_searched) { // If we found anything during this pass, we should redraw. However, we // don't want to spam too much if the page is extremely long, so if we // reach a certain point we start throttling the redraw requests.
diff --git a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc index 383579e..210149d9b 100644 --- a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc +++ b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.cc
@@ -48,9 +48,8 @@ #include "third_party/blink/public/web/web_associated_url_loader_client.h" #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" #include "third_party/blink/renderer/core/dom/document.h" -#include "third_party/blink/renderer/core/loader/document_threadable_loader.h" -#include "third_party/blink/renderer/core/loader/document_threadable_loader_client.h" -#include "third_party/blink/renderer/core/loader/threadable_loading_context.h" +#include "third_party/blink/renderer/core/loader/threadable_loader.h" +#include "third_party/blink/renderer/core/loader/threadable_loader_client.h" #include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h" #include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h" #include "third_party/blink/renderer/platform/loader/cors/cors.h" @@ -96,7 +95,7 @@ // It forwards its ThreadableLoaderClient notifications to a // WebAssociatedURLLoaderClient. class WebAssociatedURLLoaderImpl::ClientAdapter final - : public DocumentThreadableLoaderClient { + : public ThreadableLoaderClient { public: static std::unique_ptr<ClientAdapter> Create( WebAssociatedURLLoaderImpl*, @@ -119,7 +118,7 @@ void DidFail(const ResourceError&) override; void DidFailRedirectCheck() override; - // DocumentThreadableLoaderClient + // ThreadableLoaderClient bool WillFollowRedirect( const KURL& /*new_url*/, const ResourceResponse& /*redirect_response*/) override; @@ -133,7 +132,7 @@ // WebAssociatedURLLoader::loadAsynchronously() completes. void EnableErrorNotifications(); - // Stops loading and releases the DocumentThreadableLoader as early as + // Stops loading and releases the ThreadableLoader as early as // possible. WebAssociatedURLLoaderClient* ReleaseClient() { WebAssociatedURLLoaderClient* client = client_; @@ -442,9 +441,8 @@ Document* document = ToDocument(observer_->LifecycleContext()); DCHECK(document); - loader_ = DocumentThreadableLoader::Create( - *ThreadableLoadingContext::Create(*document), client_adapter_.get(), - options, resource_loader_options); + loader_ = ThreadableLoader::Create(*document, client_adapter_.get(), + options, resource_loader_options); loader_->Start(webcore_request); } @@ -518,7 +516,7 @@ // without cancelling the loader means that it's possible there're some // non-Blink non-on-heap objects still facing on-heap Blink objects. E.g. // there could be a WebURLLoader instance behind the - // DocumentThreadableLoader instance. So, for safety, we chose to just + // ThreadableLoader instance. So, for safety, we chose to just // crash here. CHECK(ThreadState::Current());
diff --git a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h index 74d27ddb..cfe041c 100644 --- a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h +++ b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl.h
@@ -17,7 +17,7 @@ namespace blink { -class DocumentThreadableLoader; +class ThreadableLoader; class WebAssociatedURLLoaderClient; class Document; @@ -57,10 +57,10 @@ WebAssociatedURLLoaderClient* client_; WebAssociatedURLLoaderOptions options_; - // An adapter which converts the DocumentThreadableLoaderClient method + // An adapter which converts the hreadableLoaderClient method // calls into the WebURLLoaderClient method calls. std::unique_ptr<ClientAdapter> client_adapter_; - Persistent<DocumentThreadableLoader> loader_; + Persistent<ThreadableLoader> loader_; // A ContextLifecycleObserver for cancelling |m_loader| when the Document // is detached.
diff --git a/third_party/blink/renderer/core/exported/web_drag_data_test.cc b/third_party/blink/renderer/core/exported/web_drag_data_test.cc index 7aa8936..2ea006b2 100644 --- a/third_party/blink/renderer/core/exported/web_drag_data_test.cc +++ b/third_party/blink/renderer/core/exported/web_drag_data_test.cc
@@ -7,6 +7,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/web_vector.h" #include "third_party/blink/renderer/core/clipboard/data_object.h" +#include "third_party/blink/renderer/platform/file_metadata.h" namespace blink {
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 9f27c5a..c9bd8d9 100644 --- a/third_party/blink/renderer/core/exported/web_frame_test.cc +++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -127,11 +127,7 @@ #include "third_party/blink/renderer/core/layout/hit_test_result.h" #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/loader/document_loader.h" -#include "third_party/blink/renderer/core/loader/document_threadable_loader.h" -#include "third_party/blink/renderer/core/loader/document_threadable_loader_client.h" #include "third_party/blink/renderer/core/loader/frame_load_request.h" -#include "third_party/blink/renderer/core/loader/threadable_loader.h" -#include "third_party/blink/renderer/core/loader/threadable_loading_context.h" #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/page/scoped_page_pauser.h" @@ -10066,21 +10062,6 @@ helper.Reset(); } -class MockDocumentThreadableLoaderClient - : public DocumentThreadableLoaderClient { - public: - MockDocumentThreadableLoaderClient() : failed_(false) {} - ~MockDocumentThreadableLoaderClient() override = default; - - // DocumentThreadableLoaderClient: - void DidFail(const ResourceError&) override { failed_ = true; } - - void Reset() { failed_ = false; } - bool Failed() { return failed_; } - - bool failed_; -}; - TEST_F(WebFrameTest, DetachRemoteFrame) { FrameTestHelpers::WebViewHelper helper; helper.InitializeRemote();
diff --git a/third_party/blink/renderer/core/fetch/fetch_data_loader.cc b/third_party/blink/renderer/core/fetch/fetch_data_loader.cc index 00c4d01d..c4cd752 100644 --- a/third_party/blink/renderer/core/fetch/fetch_data_loader.cc +++ b/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/fileapi/file.h" #include "third_party/blink/renderer/core/html/forms/form_data.h" #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h" +#include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h" #include "third_party/blink/renderer/platform/network/http_names.h" #include "third_party/blink/renderer/platform/network/parsed_content_disposition.h"
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.cc b/third_party/blink/renderer/core/fetch/fetch_manager.cc index 2f245af3..ae91026 100644 --- a/third_party/blink/renderer/core/fetch/fetch_manager.cc +++ b/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -744,8 +744,7 @@ } void FetchManager::Loader::PerformHTTPFetch(ExceptionState& exception_state) { - // CORS preflight fetch procedure is implemented inside - // DocumentThreadableLoader. + // CORS preflight fetch procedure is implemented inside ThreadableLoader. // "1. Let |HTTPRequest| be a copy of |request|, except that |HTTPRequest|'s // body is a tee of |request|'s body." @@ -837,7 +836,7 @@ // |HTTPRequest|'s origin, serialized and utf-8 encoded, to |HTTPRequest|'s // header list." // We set Origin header in updateRequestForAccessControl() called from - // DocumentThreadableLoader::makeCrossOriginAccessRequest + // ThreadableLoader::makeCrossOriginAccessRequest // "5. Let |credentials flag| be set if either |HTTPRequest|'s credentials // mode is |include|, or |HTTPRequest|'s credentials mode is |same-origin|
diff --git a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc index 48bb0a5..2f69f7c 100644 --- a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc +++ b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h" #include "third_party/blink/renderer/platform/blob/blob_data.h" +#include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/network/encoded_form_data.h" #include "third_party/blink/renderer/platform/network/form_data_encoder.h" #include "third_party/blink/renderer/platform/wtf/functional.h"
diff --git a/third_party/blink/renderer/core/fileapi/file_list_test.cc b/third_party/blink/renderer/core/fileapi/file_list_test.cc index ef6ffca..44ac730 100644 --- a/third_party/blink/renderer/core/fileapi/file_list_test.cc +++ b/third_party/blink/renderer/core/fileapi/file_list_test.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/core/fileapi/file_list.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/file_metadata.h" namespace blink {
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index 4f46e9bf..50cc1321 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -367,7 +367,6 @@ if (rect.IsEmpty()) return; canvas_is_clear_ = false; - ClearCopiedImage(); if (GetLayoutObject() && !LowLatencyEnabled()) GetLayoutObject()->SetMayNeedPaintInvalidation(); if (Is2d() && context_->ShouldAntialias() && GetPage() && @@ -757,7 +756,6 @@ size_ = size; did_fail_to_create_resource_provider_ = false; DiscardResourceProvider(); - ClearCopiedImage(); if (Is2d() && context_->isContextLost()) { context_->DidSetSurfaceSize(); } @@ -770,7 +768,7 @@ ToDataURLInternal(ImageEncoderUtils::kDefaultMimeType, 0, kFrontBuffer)); } -scoped_refptr<StaticBitmapImage> HTMLCanvasElement::ToStaticBitmapImage( +scoped_refptr<StaticBitmapImage> HTMLCanvasElement::Snapshot( SourceDrawingBuffer source_buffer, AccelerationHint hint) const { if (size_.IsEmpty()) @@ -844,7 +842,7 @@ } scoped_refptr<StaticBitmapImage> image_bitmap = - ToStaticBitmapImage(source_buffer, kPreferNoAcceleration); + Snapshot(source_buffer, kPreferNoAcceleration); if (image_bitmap) { std::unique_ptr<ImageDataBuffer> data_buffer = ImageDataBuffer::Create(image_bitmap); @@ -908,7 +906,7 @@ CanvasAsyncBlobCreator* async_creator = nullptr; scoped_refptr<StaticBitmapImage> image_bitmap = - ToStaticBitmapImage(kBackBuffer, kPreferNoAcceleration); + Snapshot(kBackBuffer, kPreferNoAcceleration); if (image_bitmap) { async_creator = CanvasAsyncBlobCreator::Create( image_bitmap, encoding_mime_type, callback, @@ -1139,57 +1137,12 @@ SetCanvas2DLayerBridgeInternal(std::move(bridge)); } -scoped_refptr<Image> HTMLCanvasElement::CopiedImage( - SourceDrawingBuffer source_buffer, - AccelerationHint hint) { - if (PlaceholderFrame()) - return PlaceholderFrame()->Bitmap(); - - if (!IsPaintable()) - return nullptr; - - if (!context_) - return CreateTransparentImage(Size()); - - if (HasImageBitmapContext()) { - scoped_refptr<Image> image = context_->GetImage(hint); - // TODO(fserb): return image? - if (image) - return context_->GetImage(hint); - // Special case: transferFromImageBitmap is not yet called. - sk_sp<SkSurface> surface = - SkSurface::MakeRasterN32Premul(width(), height()); - return StaticBitmapImage::Create(surface->makeImageSnapshot()); - } - - bool need_to_update = !copied_image_; - // The concept of SourceDrawingBuffer is valid on only WebGL. - if (context_->Is3d()) - need_to_update |= context_->PaintRenderingResultsToCanvas(source_buffer); - if (need_to_update) { - if (Is2d() && GetOrCreateCanvas2DLayerBridge()) { - copied_image_ = canvas2d_bridge_->NewImageSnapshot(hint); - } else if (Is3d() && GetOrCreateCanvasResourceProvider(hint)) { - copied_image_ = ResourceProvider()->Snapshot(); - } - UpdateMemoryUsage(); - } - return copied_image_; -} - void HTMLCanvasElement::DiscardResourceProvider() { canvas2d_bridge_.reset(); CanvasResourceHost::DiscardResourceProvider(); dirty_rect_ = FloatRect(); } -void HTMLCanvasElement::ClearCopiedImage() { - if (copied_image_) { - copied_image_ = nullptr; - UpdateMemoryUsage(); - } -} - void HTMLCanvasElement::PageVisibilityChanged() { bool hidden = !GetPage()->IsPageVisible(); SetSuspendOffscreenCanvasAnimation(hidden); @@ -1199,7 +1152,6 @@ context_->SetIsHidden(hidden); if (hidden) { - ClearCopiedImage(); if (Is3d()) { DiscardResourceProvider(); } @@ -1475,9 +1427,6 @@ } } - if (copied_image_) - non_gpu_buffer_count++; - if (Is3d()) { if (ResourceProvider()) { non_gpu_buffer_count++;
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h index 1b4daa3..bd98ac8 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -156,9 +156,6 @@ return context_.Get(); } - scoped_refptr<Image> CopiedImage(SourceDrawingBuffer, AccelerationHint); - void ClearCopiedImage(); - bool OriginClean() const override; void SetOriginTainted() override { origin_clean_ = false; } @@ -299,6 +296,9 @@ bool LowLatencyEnabled() const { return !!frame_dispatcher_; } + scoped_refptr<StaticBitmapImage> Snapshot(SourceDrawingBuffer, + AccelerationHint) const; + protected: void DidMoveToNewDocument(Document& old_document) override; @@ -331,9 +331,6 @@ bool PaintsIntoCanvasBuffer() const; - scoped_refptr<StaticBitmapImage> ToStaticBitmapImage(SourceDrawingBuffer, - AccelerationHint) const; - String ToDataURLInternal(const String& mime_type, const double& quality, SourceDrawingBuffer) const; @@ -368,10 +365,6 @@ std::unique_ptr<Canvas2DLayerBridge> canvas2d_bridge_; void ReplaceExisting2dLayerBridge(std::unique_ptr<Canvas2DLayerBridge>); - // FIXME: This is temporary for platforms that have to copy the image buffer - // to render (and for CSSCanvasValue). - mutable scoped_refptr<Image> copied_image_; - // Used for OffscreenCanvas that controls this HTML canvas element // and for low latency mode. std::unique_ptr<::blink::SurfaceLayerBridge> surface_layer_bridge_;
diff --git a/third_party/blink/renderer/core/html/html_link_element.cc b/third_party/blink/renderer/core/html/html_link_element.cc index 1139619..fc310ad5 100644 --- a/third_party/blink/renderer/core/html/html_link_element.cc +++ b/third_party/blink/renderer/core/html/html_link_element.cc
@@ -110,6 +110,8 @@ importance_ = value; } else if (name == disabledAttr) { UseCounter::Count(GetDocument(), WebFeature::kHTMLLinkElementDisabled); + if (params.reason == AttributeModificationReason::kByParser) + UseCounter::Count(GetDocument(), WebFeature::kHTMLLinkElementDisabledByParser); if (LinkStyle* link = GetLinkStyle()) link->SetDisabledState(!value.IsNull()); } else {
diff --git a/third_party/blink/renderer/core/html/html_marquee_element.cc b/third_party/blink/renderer/core/html/html_marquee_element.cc index 85588ab0..b8d3e7c 100644 --- a/third_party/blink/renderer/core/html/html_marquee_element.cc +++ b/third_party/blink/renderer/core/html/html_marquee_element.cc
@@ -291,7 +291,7 @@ double duration = 0; if (scroll_amount) duration = parameters.distance * scroll_delay / scroll_amount; - if (!duration) + if (duration <= 0) return; StringKeyframeEffectModel* effect_model = CreateEffectModel(parameters);
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc index 5387f4ab..ae3c3f03 100644 --- a/third_party/blink/renderer/core/input/event_handler.cc +++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -1766,10 +1766,9 @@ LocalFrame* hit_frame = hit_test_result.InnerNodeFrame(); if (!hit_frame) hit_frame = frame_; - location = HitTestLocation(hit_frame->View()->ConvertFromRootFrame( - LayoutPoint(adjusted_event.PositionInRootFrame()))); - hit_test_result = EventHandlingUtil::HitTestResultInFrame( - hit_frame, location, + location = HitTestLocation(adjusted_event.PositionInRootFrame()); + hit_test_result = root_frame.GetEventHandler().HitTestResultAtLocation( + location, (hit_type | HitTestRequest::kReadOnly) & ~HitTestRequest::kListBased); } // If we did a rect-based hit test it must be resolved to the best single node
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 5d8072d..6f1a106 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -4408,6 +4408,7 @@ } if (container_block->IsBox() && + container_block->IsHorizontalWritingMode() == IsHorizontalWritingMode() && ToLayoutBox(container_block)->ScrollsOverflowY() && ToLayoutBox(container_block) ->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { @@ -4764,6 +4765,15 @@ } computed_values.extent_ = logical_height_value; + if (container_block->IsBox() && + container_block->IsHorizontalWritingMode() != IsHorizontalWritingMode() && + ToLayoutBox(container_block)->ScrollsOverflowY() && + ToLayoutBox(container_block) + ->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { + logical_top_value = logical_top_value + + ToLayoutBox(container_block)->VerticalScrollbarWidth(); + } + // Use computed values to calculate the vertical position. computed_values.position_ = logical_top_value + computed_values.margins_.before_;
diff --git a/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc b/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc index 425ee90..cfa3920 100644 --- a/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc +++ b/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
@@ -467,7 +467,6 @@ LayoutGeometryMap rgm; rgm.PushMappingsToAncestor(GetLayoutBox(web_view, "A"), nullptr); - FloatPoint point; FloatRect rect(0.0f, 0.0f, 5.0f, 3.0f); EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 5.0f, 3.0f)),
diff --git a/third_party/blink/renderer/core/layout/layout_list_marker.cc b/third_party/blink/renderer/core/layout/layout_list_marker.cc index 5e34e8e..4e86707b 100644 --- a/third_party/blink/renderer/core/layout/layout_list_marker.cc +++ b/third_party/blink/renderer/core/layout/layout_list_marker.cc
@@ -296,8 +296,6 @@ std::pair<LayoutUnit, LayoutUnit> LayoutListMarker::InlineMarginsForInside( const ComputedStyle& style, bool is_image) { - LayoutUnit margin_start; - LayoutUnit margin_end; if (is_image) return {LayoutUnit(), LayoutUnit(kCMarkerPaddingPx)}; switch (GetListStyleCategory(style.ListStyleType())) {
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc index a2ff463d..e45c457 100644 --- a/third_party/blink/renderer/core/layout/layout_text.cc +++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -356,7 +356,6 @@ if (truncation == kCNoTruncation) return IntRect(); - IntRect rect; if (EllipsisBox* ellipsis = box->Root().GetEllipsisBox()) { int ellipsis_start_position = std::max<int>(start_pos - box->Start(), 0); int ellipsis_end_position = @@ -2290,7 +2289,6 @@ FloatPoint first_run_offset; if (const NGPhysicalBoxFragment* box_fragment = EnclosingBlockFlowFragment()) { - NGPhysicalOffsetRect bounding_box; const auto fragments = NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this); if (fragments.size()) {
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc index c7169116..52975440 100644 --- a/third_party/blink/renderer/core/layout/layout_view.cc +++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -262,6 +262,22 @@ } } +bool LayoutView::ShouldPlaceBlockDirectionScrollbarOnLogicalLeft() const { + LocalFrame& frame = GetFrameView()->GetFrame(); + // See crbug.com/249860 + if (frame.IsMainFrame()) + return false; + // <body> inherits 'direction' from <html>, so checking style on the body is + // sufficient. + if (Element* body = GetDocument().body()) { + if (LayoutObject* body_layout_object = body->GetLayoutObject()) { + return body_layout_object->Style() + ->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft(); + } + } + return false; +} + void LayoutView::UpdateBlockLayout(bool relayout_children) { SubtreeLayoutScope layout_scope(*this);
diff --git a/third_party/blink/renderer/core/layout/layout_view.h b/third_party/blink/renderer/core/layout/layout_view.h index fed51c0..0954c1e 100644 --- a/third_party/blink/renderer/core/layout/layout_view.h +++ b/third_party/blink/renderer/core/layout/layout_view.h
@@ -241,13 +241,7 @@ void SetShouldDoFullPaintInvalidationOnResizeIfNeeded(bool width_changed, bool height_changed); - // The document scrollbar is always on the right, even in RTL. This is to - // prevent it from moving around on navigations. - // TODO(skobes): This is not quite the ideal behavior, see - // http://crbug.com/250514 and http://crbug.com/249860. - bool ShouldPlaceBlockDirectionScrollbarOnLogicalLeft() const override { - return false; - } + bool ShouldPlaceBlockDirectionScrollbarOnLogicalLeft() const override; LayoutRect DebugRect() const override;
diff --git a/third_party/blink/renderer/core/loader/BUILD.gn b/third_party/blink/renderer/core/loader/BUILD.gn index f5b9aab..0f384d92 100644 --- a/third_party/blink/renderer/core/loader/BUILD.gn +++ b/third_party/blink/renderer/core/loader/BUILD.gn
@@ -20,9 +20,6 @@ "document_load_timing.h", "document_loader.cc", "document_loader.h", - "document_threadable_loader.cc", - "document_threadable_loader.h", - "document_threadable_loader_client.h", "empty_clients.cc", "empty_clients.h", "form_submission.cc", @@ -51,6 +48,8 @@ "link_loader.cc", "link_loader.h", "link_loader_client.h", + "long_task_detector.cc", + "long_task_detector.h", "mixed_content_checker.cc", "mixed_content_checker.h", "modulescript/document_module_script_fetcher.cc", @@ -130,8 +129,6 @@ "threadable_loading_context.h", "worker_fetch_context.cc", "worker_fetch_context.h", - "worker_threadable_loader.cc", - "worker_threadable_loader.h", ] public_deps = [
diff --git a/third_party/blink/renderer/core/loader/document_threadable_loader.cc b/third_party/blink/renderer/core/loader/document_threadable_loader.cc deleted file mode 100644 index 27721b93..0000000 --- a/third_party/blink/renderer/core/loader/document_threadable_loader.cc +++ /dev/null
@@ -1,1262 +0,0 @@ -/* - * Copyright (C) 2011, 2012 Google Inc. All rights reserved. - * Copyright (C) 2013, Intel Corporation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "third_party/blink/renderer/core/loader/document_threadable_loader.h" - -#include <memory> -#include "base/memory/weak_ptr.h" -#include "base/single_thread_task_runner.h" -#include "services/network/public/cpp/cors/cors_error_status.h" -#include "services/network/public/mojom/cors.mojom-blink.h" -#include "services/network/public/mojom/fetch_api.mojom-blink.h" -#include "third_party/blink/public/common/service_worker/service_worker_utils.h" -#include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/task_type.h" -#include "third_party/blink/public/platform/web_cors.h" -#include "third_party/blink/public/platform/web_security_origin.h" -#include "third_party/blink/public/platform/web_url_request.h" -#include "third_party/blink/renderer/core/dom/document.h" -#include "third_party/blink/renderer/core/frame/frame_console.h" -#include "third_party/blink/renderer/core/frame/local_frame.h" -#include "third_party/blink/renderer/core/frame/local_frame_client.h" -#include "third_party/blink/renderer/core/frame/web_feature.h" -#include "third_party/blink/renderer/core/inspector/console_message.h" -#include "third_party/blink/renderer/core/inspector/inspector_network_agent.h" -#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h" -#include "third_party/blink/renderer/core/loader/base_fetch_context.h" -#include "third_party/blink/renderer/core/loader/document_threadable_loader_client.h" -#include "third_party/blink/renderer/core/loader/frame_loader.h" -#include "third_party/blink/renderer/core/loader/threadable_loader_client.h" -#include "third_party/blink/renderer/core/loader/threadable_loading_context.h" -#include "third_party/blink/renderer/core/probe/core_probes.h" -#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h" -#include "third_party/blink/renderer/platform/heap/self_keep_alive.h" -#include "third_party/blink/renderer/platform/loader/cors/cors.h" -#include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h" -#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h" -#include "third_party/blink/renderer/platform/shared_buffer.h" -#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/weborigin/security_policy.h" -#include "third_party/blink/renderer/platform/wtf/assertions.h" - -namespace blink { - -namespace { - -// Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch-0 -AtomicString CreateAccessControlRequestHeadersHeader( - const HTTPHeaderMap& headers) { - Vector<String> filtered_headers; - for (const auto& header : headers) { - // Exclude CORS-safelisted headers. - if (CORS::IsCORSSafelistedHeader(header.key, header.value)) - continue; - // Calling a deprecated function, but eventually this function, - // |CreateAccessControlRequestHeadersHeader| will be removed. - // When the request is from a Worker, referrer header was added by - // WorkerThreadableLoader. But it should not be added to - // Access-Control-Request-Headers header. - if (DeprecatedEqualIgnoringCase(header.key, "referer")) - continue; - filtered_headers.push_back(header.key.DeprecatedLower()); - } - if (!filtered_headers.size()) - return g_null_atom; - - // Sort header names lexicographically. - std::sort(filtered_headers.begin(), filtered_headers.end(), - WTF::CodePointCompareLessThan); - StringBuilder header_buffer; - for (const String& header : filtered_headers) { - if (!header_buffer.IsEmpty()) - header_buffer.Append(","); - header_buffer.Append(header); - } - - return header_buffer.ToAtomicString(); -} - -class EmptyDataHandle final : public WebDataConsumerHandle { - private: - class EmptyDataReader final : public WebDataConsumerHandle::Reader { - public: - explicit EmptyDataReader( - WebDataConsumerHandle::Client* client, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) - : factory_(this) { - task_runner->PostTask( - FROM_HERE, WTF::Bind(&EmptyDataReader::Notify, factory_.GetWeakPtr(), - WTF::Unretained(client))); - } - - private: - Result BeginRead(const void** buffer, - WebDataConsumerHandle::Flags, - size_t* available) override { - *available = 0; - *buffer = nullptr; - return kDone; - } - Result EndRead(size_t) override { - return WebDataConsumerHandle::kUnexpectedError; - } - void Notify(WebDataConsumerHandle::Client* client) { - client->DidGetReadable(); - } - base::WeakPtrFactory<EmptyDataReader> factory_; - }; - - std::unique_ptr<Reader> ObtainReader( - Client* client, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) override { - return std::make_unique<EmptyDataReader>(client, std::move(task_runner)); - } - const char* DebugName() const override { return "EmptyDataHandle"; } -}; - -} // namespace - -// DetachedClient is a ThreadableLoaderClient for a "detached" -// DocumentThreadableLoader. It's for fetch requests with keepalive set, so -// it keeps itself alive during loading. -class DocumentThreadableLoader::DetachedClient final - : public GarbageCollectedFinalized<DetachedClient>, - public ThreadableLoaderClient { - public: - explicit DetachedClient(DocumentThreadableLoader* loader) - : self_keep_alive_(this), loader_(loader) {} - ~DetachedClient() override {} - - void DidFinishLoading(unsigned long identifier) override { - self_keep_alive_.Clear(); - } - void DidFail(const ResourceError&) override { self_keep_alive_.Clear(); } - void DidFailRedirectCheck() override { self_keep_alive_.Clear(); } - void Trace(Visitor* visitor) { visitor->Trace(loader_); } - - private: - SelfKeepAlive<DetachedClient> self_keep_alive_; - // Keep it alive. - const Member<DocumentThreadableLoader> loader_; -}; - -// Max number of CORS redirects handled in DocumentThreadableLoader. Same number -// as net/url_request/url_request.cc, and same number as -// https://fetch.spec.whatwg.org/#concept-http-fetch, Step 4. -// FIXME: currently the number of redirects is counted and limited here and in -// net/url_request/url_request.cc separately. -static const int kMaxCORSRedirects = 20; - -// static -void DocumentThreadableLoader::LoadResourceSynchronously( - ThreadableLoadingContext& loading_context, - const ResourceRequest& request, - ThreadableLoaderClient& client, - const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resource_loader_options) { - (new DocumentThreadableLoader(loading_context, &client, kLoadSynchronously, - options, resource_loader_options)) - ->Start(request); -} - -// static -std::unique_ptr<ResourceRequest> -DocumentThreadableLoader::CreateAccessControlPreflightRequest( - const ResourceRequest& request, - const SecurityOrigin* origin) { - const KURL& request_url = request.Url(); - - DCHECK(request_url.User().IsEmpty()); - DCHECK(request_url.Pass().IsEmpty()); - - std::unique_ptr<ResourceRequest> preflight_request = - std::make_unique<ResourceRequest>(request_url); - preflight_request->SetHTTPMethod(HTTPNames::OPTIONS); - preflight_request->SetHTTPHeaderField( - HTTPNames::Access_Control_Request_Method, request.HttpMethod()); - preflight_request->SetPriority(request.Priority()); - preflight_request->SetRequestContext(request.GetRequestContext()); - preflight_request->SetFetchCredentialsMode( - network::mojom::FetchCredentialsMode::kOmit); - preflight_request->SetSkipServiceWorker(true); - // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is - // closed and we stop storing the referrer string as a `Referer` header. - preflight_request->SetReferrerString(request.HttpReferrer()); - preflight_request->SetReferrerPolicy(request.GetReferrerPolicy()); - - if (request.IsExternalRequest()) { - preflight_request->SetHTTPHeaderField( - HTTPNames::Access_Control_Request_External, "true"); - } - - const AtomicString request_headers = - CreateAccessControlRequestHeadersHeader(request.HttpHeaderFields()); - if (request_headers != g_null_atom) { - preflight_request->SetHTTPHeaderField( - HTTPNames::Access_Control_Request_Headers, request_headers); - } - - if (origin) - preflight_request->SetHTTPOrigin(origin); - - return preflight_request; -} - -// static -std::unique_ptr<ResourceRequest> -DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting( - const ResourceRequest& request) { - return CreateAccessControlPreflightRequest(request, nullptr); -} - -// static -DocumentThreadableLoader* DocumentThreadableLoader::Create( - ThreadableLoadingContext& loading_context, - ThreadableLoaderClient* client, - const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resource_loader_options) { - return new DocumentThreadableLoader(loading_context, client, - kLoadAsynchronously, options, - resource_loader_options); -} - -DocumentThreadableLoader::DocumentThreadableLoader( - ThreadableLoadingContext& loading_context, - ThreadableLoaderClient* client, - BlockingBehavior blocking_behavior, - const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resource_loader_options) - : client_(client), - loading_context_(&loading_context), - options_(options), - resource_loader_options_(resource_loader_options), - out_of_blink_cors_(RuntimeEnabledFeatures::OutOfBlinkCORSEnabled()), - cors_flag_(false), - security_origin_(resource_loader_options_.security_origin), - is_using_data_consumer_handle_(false), - async_(blocking_behavior == kLoadAsynchronously), - request_context_(WebURLRequest::kRequestContextUnspecified), - fetch_request_mode_(network::mojom::FetchRequestMode::kSameOrigin), - fetch_credentials_mode_(network::mojom::FetchCredentialsMode::kOmit), - timeout_timer_( - GetExecutionContext()->GetTaskRunner(TaskType::kNetworking), - this, - &DocumentThreadableLoader::DidTimeout), - cors_redirect_limit_(0), - redirect_mode_(network::mojom::FetchRedirectMode::kFollow), - override_referrer_(false) { - DCHECK(client); -} - -void DocumentThreadableLoader::Start(const ResourceRequest& request) { - // Setting an outgoing referer is only supported in the async code path. - DCHECK(async_ || request.HttpReferrer().IsEmpty()); - - bool cors_enabled = - CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()); - - // kPreventPreflight can be used only when the CORS is enabled. - DCHECK(request.CORSPreflightPolicy() == - network::mojom::CORSPreflightPolicy::kConsiderPreflight || - cors_enabled); - - if (cors_enabled) - cors_redirect_limit_ = kMaxCORSRedirects; - - request_context_ = request.GetRequestContext(); - fetch_request_mode_ = request.GetFetchRequestMode(); - fetch_credentials_mode_ = request.GetFetchCredentialsMode(); - redirect_mode_ = request.GetFetchRedirectMode(); - - if (request.GetFetchRequestMode() == - network::mojom::FetchRequestMode::kNoCORS) { - SECURITY_CHECK(WebCORS::IsNoCORSAllowedContext(request_context_)); - } else { - cors_flag_ = !GetSecurityOrigin()->CanRequest(request.Url()); - } - - // The CORS flag variable is not yet used at the step in the spec that - // corresponds to this line, but divert |cors_flag_| here for convenience. - if (cors_flag_ && request.GetFetchRequestMode() == - network::mojom::FetchRequestMode::kSameOrigin) { - ThreadableLoaderClient* client = client_; - Clear(); - ResourceError error = ResourceError::CancelledDueToAccessCheckError( - request.Url(), ResourceRequestBlockedReason::kOther, - CORS::GetErrorString( - CORS::ErrorParameter::CreateForDisallowedByMode(request.Url()))); - GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create( - kJSMessageSource, kErrorMessageLevel, error.LocalizedDescription())); - client->DidFail(error); - return; - } - - request_started_ = CurrentTimeTicks(); - - // Save any headers on the request here. If this request redirects - // cross-origin, we cancel the old request create a new one, and copy these - // headers. - request_headers_ = request.HttpHeaderFields(); - - ResourceRequest new_request(request); - - // Set the service worker mode to none if "bypass for network" in DevTools is - // enabled. - bool should_bypass_service_worker = false; - probe::shouldBypassServiceWorker(GetExecutionContext(), - &should_bypass_service_worker); - if (should_bypass_service_worker) - new_request.SetSkipServiceWorker(true); - - // In S13nServiceWorker, if the controller service worker has no fetch event - // handler, it's skipped entirely, so we should treat that case the same as - // having no controller. In non-S13nServiceWorker, we can't do that since we - // don't know which service worker will handle the request since it's - // determined on the browser process and skipWaiting() can happen in the - // meantime. - // - // TODO(crbug.com/715640): When non-S13nServiceWorker is removed, - // is_controlled_by_service_worker is the same as - // ControllerServiceWorkerMode::kControlled, so this code can be simplified. - bool is_controlled_by_service_worker = false; - switch ( - loading_context_->GetResourceFetcher()->IsControlledByServiceWorker()) { - case blink::mojom::ControllerServiceWorkerMode::kControlled: - is_controlled_by_service_worker = true; - break; - case blink::mojom::ControllerServiceWorkerMode::kNoFetchEventHandler: - if (ServiceWorkerUtils::IsServicificationEnabled()) - is_controlled_by_service_worker = false; - else - is_controlled_by_service_worker = true; - break; - case blink::mojom::ControllerServiceWorkerMode::kNoController: - is_controlled_by_service_worker = false; - break; - } - - // Process the CORS protocol inside the DocumentThreadableLoader for the - // following cases: - // - // - When the request is sync or the protocol is unsupported since we can - // assume that any service worker (SW) is skipped for such requests by - // content/ code. - // - When |skip_service_worker| is true, any SW will be skipped. - // - If we're not yet controlled by a SW, then we're sure that this - // request won't be intercepted by a SW. In case we end up with - // sending a CORS preflight request, the actual request to be sent later - // may be intercepted. This is taken care of in LoadPreflightRequest() by - // setting |skip_service_worker| to true. - // - // From the above analysis, you can see that the request can never be - // intercepted by a SW inside this if-block. It's because: - // - |skip_service_worker| needs to be false, and - // - we're controlled by a SW at this point - // to allow a SW to intercept the request. Even when the request gets issued - // asynchronously after performing the CORS preflight, it doesn't get - // intercepted since LoadPreflightRequest() sets the flag to kNone in advance. - if (!async_ || new_request.GetSkipServiceWorker() || - !SchemeRegistry::ShouldTreatURLSchemeAsAllowingServiceWorkers( - new_request.Url().Protocol()) || - !is_controlled_by_service_worker) { - DispatchInitialRequest(new_request); - return; - } - - if (CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode())) { - // Save the request to fallback_request_for_service_worker to use when the - // service worker doesn't handle (call respondWith()) a CORS enabled - // request. - fallback_request_for_service_worker_ = ResourceRequest(request); - // Skip the service worker for the fallback request. - fallback_request_for_service_worker_.SetSkipServiceWorker(true); - } - - LoadRequest(new_request, resource_loader_options_); -} - -void DocumentThreadableLoader::DispatchInitialRequest( - ResourceRequest& request) { - if (out_of_blink_cors_ || (!request.IsExternalRequest() && !cors_flag_)) { - LoadRequest(request, resource_loader_options_); - return; - } - - DCHECK(CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()) || - request.IsExternalRequest()); - - MakeCrossOriginAccessRequest(request); -} - -void DocumentThreadableLoader::PrepareCrossOriginRequest( - ResourceRequest& request) const { - if (GetSecurityOrigin()) - request.SetHTTPOrigin(GetSecurityOrigin()); - - // TODO(domfarolino): Stop setting the HTTPReferrer header, and instead use - // ResourceRequest::referrer_. See https://crbug.com/850813. - if (override_referrer_) - request.SetHTTPReferrer(referrer_after_redirect_); -} - -void DocumentThreadableLoader::LoadPreflightRequest( - const ResourceRequest& actual_request, - const ResourceLoaderOptions& actual_options) { - std::unique_ptr<ResourceRequest> preflight_request = - CreateAccessControlPreflightRequest(actual_request, GetSecurityOrigin()); - - actual_request_ = actual_request; - actual_options_ = actual_options; - - // Explicitly set |skip_service_worker| to true here. Although the page is - // not controlled by a SW at this point, a new SW may be controlling the - // page when this actual request gets sent later. We should not send the - // actual request to the SW. See https://crbug.com/604583. - actual_request_.SetSkipServiceWorker(true); - - // Create a ResourceLoaderOptions for preflight. - ResourceLoaderOptions preflight_options = actual_options; - - LoadRequest(*preflight_request, preflight_options); -} - -void DocumentThreadableLoader::MakeCrossOriginAccessRequest( - const ResourceRequest& request) { - DCHECK(CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()) || - request.IsExternalRequest()); - DCHECK(client_); - DCHECK(!GetResource()); - - // Cross-origin requests are only allowed certain registered schemes. We would - // catch this when checking response headers later, but there is no reason to - // send a request, preflighted or not, that's guaranteed to be denied. - if (!SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled( - request.Url().Protocol())) { - DispatchDidFailAccessControlCheck( - ResourceError::CancelledDueToAccessCheckError( - request.Url(), ResourceRequestBlockedReason::kOther, - String::Format( - "Cross origin requests are only supported for protocol " - "schemes: %s.", - SchemeRegistry::ListOfCORSEnabledURLSchemes().Ascii().data()))); - return; - } - - // Non-secure origins may not make "external requests": - // https://wicg.github.io/cors-rfc1918/#integration-fetch - String error_message; - if (!GetExecutionContext()->IsSecureContext(error_message) && - request.IsExternalRequest()) { - DispatchDidFailAccessControlCheck( - ResourceError::CancelledDueToAccessCheckError( - request.Url(), ResourceRequestBlockedReason::kOrigin, - "Requests to internal network resources are not allowed " - "from non-secure contexts (see https://goo.gl/Y0ZkNV). " - "This is an experimental restriction which is part of " - "'https://mikewest.github.io/cors-rfc1918/'.")); - return; - } - - ResourceRequest cross_origin_request(request); - ResourceLoaderOptions cross_origin_options(resource_loader_options_); - - cross_origin_request.RemoveUserAndPassFromURL(); - - // Enforce the CORS preflight for checking the Access-Control-Allow-External - // header. The CORS preflight cache doesn't help for this purpose. - if (request.IsExternalRequest()) { - LoadPreflightRequest(cross_origin_request, cross_origin_options); - return; - } - - if (request.GetFetchRequestMode() != - network::mojom::FetchRequestMode::kCORSWithForcedPreflight) { - if (request.CORSPreflightPolicy() == - network::mojom::CORSPreflightPolicy::kPreventPreflight) { - PrepareCrossOriginRequest(cross_origin_request); - LoadRequest(cross_origin_request, cross_origin_options); - return; - } - - DCHECK_EQ(request.CORSPreflightPolicy(), - network::mojom::CORSPreflightPolicy::kConsiderPreflight); - - // We use ContainsOnlyCORSSafelistedOrForbiddenHeaders() here since - // |request| may have been modified in the process of loading (not from - // the user's input). For example, referrer. We need to accept them. For - // security, we must reject forbidden headers/methods at the point we - // accept user's input. Not here. - if (CORS::IsCORSSafelistedMethod(request.HttpMethod()) && - CORS::ContainsOnlyCORSSafelistedOrForbiddenHeaders( - request.HttpHeaderFields())) { - PrepareCrossOriginRequest(cross_origin_request); - LoadRequest(cross_origin_request, cross_origin_options); - return; - } - } - - // Now, we need to check that the request passes the CORS preflight either by - // issuing a CORS preflight or based on an entry in the CORS preflight cache. - - bool should_ignore_preflight_cache = false; - // Prevent use of the CORS preflight cache when instructed by the DevTools - // not to use caches. - probe::shouldForceCORSPreflight(GetExecutionContext(), - &should_ignore_preflight_cache); - if (should_ignore_preflight_cache || - !CORS::CheckIfRequestCanSkipPreflight( - GetSecurityOrigin()->ToString(), cross_origin_request.Url(), - cross_origin_request.GetFetchCredentialsMode(), - cross_origin_request.HttpMethod(), - cross_origin_request.HttpHeaderFields())) { - LoadPreflightRequest(cross_origin_request, cross_origin_options); - return; - } - - // We don't want any requests that could involve a CORS preflight to get - // intercepted by a foreign SW, even if we have the result of the preflight - // cached already. See https://crbug.com/674370. - cross_origin_request.SetSkipServiceWorker(true); - - PrepareCrossOriginRequest(cross_origin_request); - LoadRequest(cross_origin_request, cross_origin_options); -} - -DocumentThreadableLoader::~DocumentThreadableLoader() { - // |client_| is a raw pointer and having a non-null |client_| here probably - // means UaF. - // In the detached case, |this| is held by DetachedClient defined above, but - // SelfKeepAlive in DetachedClient is forcibly cancelled on worker thread - // termination. We can safely ignore this case. - CHECK(!client_ || detached_); - DCHECK(!GetResource()); -} - -void DocumentThreadableLoader::OverrideTimeout( - unsigned long timeout_milliseconds) { - DCHECK(async_); - - // |m_requestStartedSeconds| == 0.0 indicates loading is already finished and - // |m_timeoutTimer| is already stopped, and thus we do nothing for such cases. - // See https://crbug.com/551663 for details. - if (request_started_ <= TimeTicks()) - return; - - timeout_timer_.Stop(); - // At the time of this method's implementation, it is only ever called by - // XMLHttpRequest, when the timeout attribute is set after sending the - // request. - // - // The XHR request says to resolve the time relative to when the request - // was initially sent, however other uses of this method may need to - // behave differently, in which case this should be re-arranged somehow. - if (timeout_milliseconds) { - TimeDelta elapsed_time = CurrentTimeTicks() - request_started_; - TimeDelta next_fire = TimeDelta::FromMilliseconds(timeout_milliseconds); - TimeDelta resolved_time = std::max(next_fire - elapsed_time, TimeDelta()); - timeout_timer_.StartOneShot(resolved_time, FROM_HERE); - } -} - -void DocumentThreadableLoader::Cancel() { - // Cancel can re-enter, and therefore |resource()| might be null here as a - // result. - if (!client_ || !GetResource()) { - Clear(); - return; - } - - DispatchDidFail(ResourceError::CancelledError(GetResource()->Url())); -} - -void DocumentThreadableLoader::Detach() { - Resource* resource = GetResource(); - if (!resource) - return; - detached_ = true; - client_ = new DetachedClient(this); -} - -void DocumentThreadableLoader::SetDefersLoading(bool value) { - if (GetResource() && GetResource()->Loader()) - GetResource()->Loader()->SetDefersLoading(value); -} - -void DocumentThreadableLoader::Clear() { - client_ = nullptr; - timeout_timer_.Stop(); - request_started_ = TimeTicks(); - if (GetResource()) - checker_.WillRemoveClient(); - ClearResource(); -} - -// In this method, we can clear |request| to tell content::WebURLLoaderImpl of -// Chromium not to follow the redirect. This works only when this method is -// called by RawResource::willSendRequest(). If called by -// RawResource::didAddClient(), clearing |request| won't be propagated to -// content::WebURLLoaderImpl. So, this loader must also get detached from the -// resource by calling clearResource(). -// TODO(toyoshim): Implement OOR-CORS mode specific redirect code. -bool DocumentThreadableLoader::RedirectReceived( - Resource* resource, - const ResourceRequest& new_request, - const ResourceResponse& redirect_response) { - DCHECK(client_); - DCHECK_EQ(resource, GetResource()); - - checker_.RedirectReceived(); - - const KURL& new_url = new_request.Url(); - const KURL& original_url = redirect_response.Url(); - - if (!actual_request_.IsNull()) { - DCHECK(!out_of_blink_cors_); - ReportResponseReceived(resource->Identifier(), redirect_response); - - HandlePreflightFailure( - original_url, CORS::GetErrorString( - CORS::ErrorParameter::CreateForDisallowedRedirect())); - - return false; - } - - if (redirect_mode_ == network::mojom::FetchRedirectMode::kManual) { - // We use |redirect_mode_| to check the original redirect mode. - // |new_request| is a new request for redirect. So we don't set the - // redirect mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect(). - DCHECK(new_request.UseStreamOnResponse()); - // There is no need to read the body of redirect response because there is - // no way to read the body of opaque-redirect filtered response's internal - // response. - // TODO(horo): If we support any API which expose the internal body, we will - // have to read the body. And also HTTPCache changes will be needed because - // it doesn't store the body of redirect responses. - ResponseReceived(resource, redirect_response, - std::make_unique<EmptyDataHandle>()); - - if (client_) { - DCHECK(actual_request_.IsNull()); - NotifyFinished(resource); - } - - return false; - } - - if (redirect_mode_ == network::mojom::FetchRedirectMode::kError) { - ThreadableLoaderClient* client = client_; - Clear(); - client->DidFailRedirectCheck(); - - return false; - } - - if (out_of_blink_cors_) { - client_->DidReceiveRedirectTo(new_url); - if (client_->IsDocumentThreadableLoaderClient()) { - return static_cast<DocumentThreadableLoaderClient*>(client_) - ->WillFollowRedirect(new_url, redirect_response); - } - return true; - } - - // Allow same origin requests to continue after allowing clients to audit the - // redirect. - if (IsAllowedRedirect(new_request.GetFetchRequestMode(), new_url)) { - client_->DidReceiveRedirectTo(new_url); - if (client_->IsDocumentThreadableLoaderClient()) { - return static_cast<DocumentThreadableLoaderClient*>(client_) - ->WillFollowRedirect(new_url, redirect_response); - } - return true; - } - - if (cors_redirect_limit_ <= 0) { - ThreadableLoaderClient* client = client_; - Clear(); - client->DidFailRedirectCheck(); - return false; - } - - --cors_redirect_limit_; - - probe::didReceiveCORSRedirectResponse( - GetExecutionContext(), resource->Identifier(), - GetDocument() && GetDocument()->GetFrame() - ? GetDocument()->GetFrame()->Loader().GetDocumentLoader() - : nullptr, - redirect_response, resource); - - base::Optional<network::mojom::CORSError> redirect_error = - CORS::CheckRedirectLocation(new_url); - if (redirect_error) { - DispatchDidFailAccessControlCheck( - ResourceError::CancelledDueToAccessCheckError( - original_url, ResourceRequestBlockedReason::kOther, - CORS::GetErrorString(CORS::ErrorParameter::CreateForRedirectCheck( - *redirect_error, original_url, new_url)))); - return false; - } - - if (cors_flag_) { - // The redirect response must pass the access control check if the CORS - // flag is set. - base::Optional<network::CORSErrorStatus> access_error = CORS::CheckAccess( - original_url, redirect_response.HttpStatusCode(), - redirect_response.HttpHeaderFields(), - new_request.GetFetchCredentialsMode(), *GetSecurityOrigin()); - if (access_error) { - DispatchDidFailAccessControlCheck( - ResourceError::CancelledDueToAccessCheckError( - original_url, ResourceRequestBlockedReason::kOther, - CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck( - *access_error, original_url, - redirect_response.HttpStatusCode(), *GetSecurityOrigin(), - request_context_, new_url)))); - return false; - } - } - - client_->DidReceiveRedirectTo(new_url); - - // FIXME: consider combining this with CORS redirect handling performed by - // CrossOriginAccessControl::handleRedirect(). - if (GetResource()) - checker_.WillRemoveClient(); - ClearResource(); - - // If - // - CORS flag is set, and - // - the origin of the redirect target URL is not same origin with the origin - // of the current request's URL - // set the source origin to a unique opaque origin. - // - // See https://fetch.spec.whatwg.org/#http-redirect-fetch. - if (cors_flag_) { - scoped_refptr<const SecurityOrigin> original_origin = - SecurityOrigin::Create(original_url); - scoped_refptr<const SecurityOrigin> new_origin = - SecurityOrigin::Create(new_url); - if (!original_origin->IsSameSchemeHostPort(new_origin.get())) - security_origin_ = SecurityOrigin::CreateUniqueOpaque(); - } - - // Set |cors_flag_| so that further logic (corresponds to the main fetch in - // the spec) will be performed with CORS flag set. - // See https://fetch.spec.whatwg.org/#http-redirect-fetch. - cors_flag_ = true; - - // Save the referrer to use when following the redirect. - override_referrer_ = true; - // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is - // closed and we stop storing the referrer string as a `Referer` header. - referrer_after_redirect_ = - Referrer(new_request.HttpReferrer(), new_request.GetReferrerPolicy()); - - ResourceRequest cross_origin_request(new_request); - - // Remove any headers that may have been added by the network layer that cause - // access control to fail. - cross_origin_request.ClearHTTPReferrer(); - cross_origin_request.ClearHTTPOrigin(); - cross_origin_request.ClearHTTPUserAgent(); - // Add any request headers which we previously saved from the - // original request. - for (const auto& header : request_headers_) - cross_origin_request.SetHTTPHeaderField(header.key, header.value); - MakeCrossOriginAccessRequest(cross_origin_request); - - return false; -} - -void DocumentThreadableLoader::RedirectBlocked() { - checker_.RedirectBlocked(); - - // Tells the client that a redirect was received but not followed (for an - // unknown reason). - ThreadableLoaderClient* client = client_; - Clear(); - client->DidFailRedirectCheck(); -} - -void DocumentThreadableLoader::DataSent( - Resource* resource, - unsigned long long bytes_sent, - unsigned long long total_bytes_to_be_sent) { - DCHECK(client_); - DCHECK_EQ(resource, GetResource()); - DCHECK(async_); - - checker_.DataSent(); - client_->DidSendData(bytes_sent, total_bytes_to_be_sent); -} - -void DocumentThreadableLoader::DataDownloaded(Resource* resource, - int data_length) { - DCHECK(client_); - DCHECK_EQ(resource, GetResource()); - DCHECK(actual_request_.IsNull()); - - checker_.DataDownloaded(); - client_->DidDownloadData(data_length); -} - -void DocumentThreadableLoader::DidReceiveResourceTiming( - Resource* resource, - const ResourceTimingInfo& info) { - DCHECK(client_); - DCHECK_EQ(resource, GetResource()); - - client_->DidReceiveResourceTiming(info); -} - -void DocumentThreadableLoader::DidDownloadToBlob( - Resource* resource, - scoped_refptr<BlobDataHandle> blob) { - DCHECK(client_); - DCHECK_EQ(resource, GetResource()); - - checker_.DidDownloadToBlob(); - client_->DidDownloadToBlob(std::move(blob)); -} - - -void DocumentThreadableLoader::HandlePreflightResponse( - const ResourceResponse& response) { - base::Optional<network::CORSErrorStatus> cors_error_status = - CORS::CheckPreflightAccess(response.Url(), response.HttpStatusCode(), - response.HttpHeaderFields(), - actual_request_.GetFetchCredentialsMode(), - *GetSecurityOrigin()); - if (cors_error_status) { - HandlePreflightFailure( - response.Url(), - CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck( - *cors_error_status, response.Url(), 0 /* status_code */, - *GetSecurityOrigin(), request_context_))); - return; - } - - base::Optional<network::mojom::CORSError> preflight_error = - CORS::CheckPreflight(response.HttpStatusCode()); - if (preflight_error) { - HandlePreflightFailure( - response.Url(), CORS::GetErrorString( - CORS::ErrorParameter::CreateForPreflightStatusCheck( - response.HttpStatusCode()))); - return; - } - - if (actual_request_.IsExternalRequest()) { - base::Optional<network::CORSErrorStatus> external_preflight_status = - CORS::CheckExternalPreflight(response.HttpHeaderFields()); - if (external_preflight_status) { - HandlePreflightFailure( - response.Url(), - CORS::GetErrorString( - CORS::ErrorParameter::CreateForExternalPreflightCheck( - *external_preflight_status))); - return; - } - } - - String access_control_error_description; - if (!CORS::EnsurePreflightResultAndCacheOnSuccess( - response.HttpHeaderFields(), GetSecurityOrigin()->ToString(), - actual_request_.Url(), actual_request_.HttpMethod(), - actual_request_.HttpHeaderFields(), - actual_request_.GetFetchCredentialsMode(), - &access_control_error_description)) { - HandlePreflightFailure(response.Url(), access_control_error_description); - } -} - -void DocumentThreadableLoader::ReportResponseReceived( - unsigned long identifier, - const ResourceResponse& response) { - LocalFrame* frame = GetDocument() ? GetDocument()->GetFrame() : nullptr; - if (!frame) - return; - DocumentLoader* loader = frame->Loader().GetDocumentLoader(); - probe::didReceiveResourceResponse(GetExecutionContext(), identifier, loader, - response, GetResource()); - frame->Console().ReportResourceResponseReceived(loader, identifier, response); -} - -void DocumentThreadableLoader::ResponseReceived( - Resource* resource, - const ResourceResponse& response, - std::unique_ptr<WebDataConsumerHandle> handle) { - DCHECK_EQ(resource, GetResource()); - DCHECK(client_); - - checker_.ResponseReceived(); - - if (handle) - is_using_data_consumer_handle_ = true; - - // TODO(toyoshim): Support OOR-CORS preflight and Service Worker case. - // Note that CORS-preflight is usually handled in the Network Service side, - // but still done in Blink side when it is needed on redirects. - // https://crbug.com/736308. - if (out_of_blink_cors_ && !response.WasFetchedViaServiceWorker()) { - DCHECK(actual_request_.IsNull()); - fallback_request_for_service_worker_ = ResourceRequest(); - client_->DidReceiveResponse(resource->Identifier(), response, - std::move(handle)); - return; - } - - // Code path for legacy Blink CORS. - if (!actual_request_.IsNull()) { - ReportResponseReceived(resource->Identifier(), response); - HandlePreflightResponse(response); - return; - } - - if (response.WasFetchedViaServiceWorker()) { - if (response.WasFallbackRequiredByServiceWorker()) { - // At this point we must have m_fallbackRequestForServiceWorker. (For - // SharedWorker the request won't be CORS or CORS-with-preflight, - // therefore fallback-to-network is handled in the browser process when - // the ServiceWorker does not call respondWith().) - DCHECK(!fallback_request_for_service_worker_.IsNull()); - ReportResponseReceived(resource->Identifier(), response); - LoadFallbackRequestForServiceWorker(); - return; - } - - // It's possible that we issue a fetch with request with non "no-cors" - // mode but get an opaque filtered response if a service worker is involved. - // We dispatch a CORS failure for the case. - // TODO(yhirano): This is probably not spec conformant. Fix it after - // https://github.com/w3c/preload/issues/100 is addressed. - if (fetch_request_mode_ != network::mojom::FetchRequestMode::kNoCORS && - response.ResponseTypeViaServiceWorker() == - network::mojom::FetchResponseType::kOpaque) { - DispatchDidFailAccessControlCheck( - ResourceError::CancelledDueToAccessCheckError( - response.Url(), ResourceRequestBlockedReason::kOther, - CORS::GetErrorString( - CORS::ErrorParameter::CreateForInvalidResponse( - response.Url(), *GetSecurityOrigin())))); - return; - } - - fallback_request_for_service_worker_ = ResourceRequest(); - client_->DidReceiveResponse(resource->Identifier(), response, - std::move(handle)); - return; - } - - // Even if the request met the conditions to get handled by a Service Worker - // in the constructor of this class (and therefore - // |m_fallbackRequestForServiceWorker| is set), the Service Worker may skip - // processing the request. Only if the request is same origin, the skipped - // response may come here (wasFetchedViaServiceWorker() returns false) since - // such a request doesn't have to go through the CORS algorithm by calling - // loadFallbackRequestForServiceWorker(). - DCHECK(fallback_request_for_service_worker_.IsNull() || - GetSecurityOrigin()->CanRequest( - fallback_request_for_service_worker_.Url())); - fallback_request_for_service_worker_ = ResourceRequest(); - - if (CORS::IsCORSEnabledRequestMode(fetch_request_mode_) && cors_flag_) { - base::Optional<network::CORSErrorStatus> access_error = CORS::CheckAccess( - response.Url(), response.HttpStatusCode(), response.HttpHeaderFields(), - fetch_credentials_mode_, *GetSecurityOrigin()); - if (access_error) { - ReportResponseReceived(resource->Identifier(), response); - DispatchDidFailAccessControlCheck( - ResourceError::CancelledDueToAccessCheckError( - response.Url(), ResourceRequestBlockedReason::kOther, - CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck( - *access_error, response.Url(), response.HttpStatusCode(), - *GetSecurityOrigin(), request_context_)))); - return; - } - } - - client_->DidReceiveResponse(resource->Identifier(), response, - std::move(handle)); -} - -void DocumentThreadableLoader::SetSerializedCachedMetadata(Resource*, - const char* data, - size_t size) { - checker_.SetSerializedCachedMetadata(); - - if (!actual_request_.IsNull()) - return; - client_->DidReceiveCachedMetadata(data, size); -} - -void DocumentThreadableLoader::DataReceived(Resource* resource, - const char* data, - size_t data_length) { - DCHECK_EQ(resource, GetResource()); - DCHECK(client_); - - checker_.DataReceived(); - - if (is_using_data_consumer_handle_) - return; - - // Preflight data should be invisible to clients. - if (!actual_request_.IsNull()) - return; - - DCHECK(fallback_request_for_service_worker_.IsNull()); - - // TODO(junov): Fix the ThreadableLoader ecosystem to use size_t. Until then, - // we use safeCast to trap potential overflows. - client_->DidReceiveData(data, SafeCast<unsigned>(data_length)); -} - -void DocumentThreadableLoader::NotifyFinished(Resource* resource) { - DCHECK(client_); - DCHECK_EQ(resource, GetResource()); - - checker_.NotifyFinished(resource); - - // Don't throw an exception for failed sync local file loads. - // TODO(japhet): This logic has been moved around but unchanged since 2007. - // Tested by fast/xmlhttprequest/xmlhttprequest-missing-file-exception.html - // Do we still need this? - bool is_sync_to_local_file = resource->Url().IsLocalFile() && !async_; - - if (resource->ErrorOccurred() && !is_sync_to_local_file) { - DispatchDidFail(resource->GetResourceError()); - return; - } - - DCHECK(fallback_request_for_service_worker_.IsNull()); - - if (!actual_request_.IsNull()) { - DCHECK(actual_request_.IsExternalRequest() || cors_flag_); - LoadActualRequest(); - return; - } - - ThreadableLoaderClient* client = client_; - // Protect the resource in |didFinishLoading| in order not to release the - // downloaded file. - Persistent<Resource> protect = GetResource(); - Clear(); - client->DidFinishLoading(resource->Identifier()); -} - -void DocumentThreadableLoader::DidTimeout(TimerBase* timer) { - DCHECK(async_); - DCHECK_EQ(timer, &timeout_timer_); - // clearResource() may be called in clear() and some other places. clear() - // calls stop() on |m_timeoutTimer|. In the other places, the resource is set - // again. If the creation fails, clear() is called. So, here, resource() is - // always non-nullptr. - DCHECK(GetResource()); - // When |m_client| is set to nullptr only in clear() where |m_timeoutTimer| - // is stopped. So, |m_client| is always non-nullptr here. - DCHECK(client_); - - DispatchDidFail(ResourceError::TimeoutError(GetResource()->Url())); -} - -void DocumentThreadableLoader::LoadFallbackRequestForServiceWorker() { - if (GetResource()) - checker_.WillRemoveClient(); - ClearResource(); - ResourceRequest fallback_request(fallback_request_for_service_worker_); - fallback_request_for_service_worker_ = ResourceRequest(); - DispatchInitialRequest(fallback_request); -} - -void DocumentThreadableLoader::LoadActualRequest() { - ResourceRequest actual_request = actual_request_; - ResourceLoaderOptions actual_options = actual_options_; - actual_request_ = ResourceRequest(); - actual_options_ = ResourceLoaderOptions(); - - if (GetResource()) - checker_.WillRemoveClient(); - ClearResource(); - - PrepareCrossOriginRequest(actual_request); - LoadRequest(actual_request, actual_options); -} - -void DocumentThreadableLoader::HandlePreflightFailure( - const KURL& url, - const String& error_description) { - // Prevent NotifyFinished() from bypassing access check. - actual_request_ = ResourceRequest(); - - DispatchDidFailAccessControlCheck( - ResourceError::CancelledDueToAccessCheckError( - url, ResourceRequestBlockedReason::kOther, error_description)); -} - -void DocumentThreadableLoader::DispatchDidFailAccessControlCheck( - const ResourceError& error) { - const String message = "Failed to load " + error.FailingURL() + ": " + - error.LocalizedDescription(); - GetExecutionContext()->AddConsoleMessage( - ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel, message)); - - ThreadableLoaderClient* client = client_; - Clear(); - client->DidFail(error); -} - -void DocumentThreadableLoader::DispatchDidFail(const ResourceError& error) { - if (error.CORSErrorStatus()) { - DCHECK(out_of_blink_cors_); - // TODO(toyoshim): Should consider to pass correct arguments instead of - // KURL(), and 0 to GetErrorString(). - // We still need plumbing some more information. - GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create( - kJSMessageSource, kErrorMessageLevel, - "Failed to load " + error.FailingURL() + ": " + - CORS::GetErrorString(CORS::ErrorParameter::Create( - *error.CORSErrorStatus(), - KURL(error.FailingURL()), KURL(), 0, - *GetSecurityOrigin(), request_context_)) - .Utf8() - .data())); - } - ThreadableLoaderClient* client = client_; - Clear(); - client->DidFail(error); -} - - -void DocumentThreadableLoader::LoadRequest( - ResourceRequest& request, - ResourceLoaderOptions resource_loader_options) { - resource_loader_options.cors_handling_by_resource_fetcher = - kDisableCORSHandlingByResourceFetcher; - - bool allow_stored_credentials = false; - switch (request.GetFetchCredentialsMode()) { - case network::mojom::FetchCredentialsMode::kOmit: - break; - case network::mojom::FetchCredentialsMode::kSameOrigin: - // TODO(toyoshim): It's wrong to use |cors_flag| here. Fix it to use the - // response tainting. - // - // TODO(toyoshim): The credentials mode must work even when the "no-cors" - // mode is in use. See the following issues: - // - https://github.com/whatwg/fetch/issues/130 - // - https://github.com/whatwg/fetch/issues/169 - allow_stored_credentials = !cors_flag_; - break; - case network::mojom::FetchCredentialsMode::kInclude: - allow_stored_credentials = true; - break; - } - request.SetAllowStoredCredentials(allow_stored_credentials); - - resource_loader_options.security_origin = security_origin_; - - if (!actual_request_.IsNull()) - resource_loader_options.data_buffering_policy = kBufferData; - - TimeDelta timeout = - TimeDelta::FromMilliseconds(options_.timeout_milliseconds); - if (options_.timeout_milliseconds > 0) { - if (!async_) { - request.SetTimeoutInterval(timeout); - } else if (!timeout_timer_.IsActive()) { - // The timer can be active if this is the actual request of a - // CORS-with-preflight request. - timeout_timer_.StartOneShot(timeout, FROM_HERE); - } - } - - FetchParameters new_params(request, resource_loader_options); - DCHECK(!GetResource()); - - checker_.WillAddClient(); - ResourceFetcher* fetcher = loading_context_->GetResourceFetcher(); - if (request.GetRequestContext() == WebURLRequest::kRequestContextVideo || - request.GetRequestContext() == WebURLRequest::kRequestContextAudio) { - DCHECK(async_); - RawResource::FetchMedia(new_params, fetcher, this); - } else if (request.GetRequestContext() == - WebURLRequest::kRequestContextManifest) { - DCHECK(async_); - RawResource::FetchManifest(new_params, fetcher, this); - } else if (async_) { - RawResource::Fetch(new_params, fetcher, this); - } else { - RawResource::FetchSynchronously(new_params, fetcher, this); - } -} - -bool DocumentThreadableLoader::IsAllowedRedirect( - network::mojom::FetchRequestMode fetch_request_mode, - const KURL& url) const { - if (fetch_request_mode == network::mojom::FetchRequestMode::kNoCORS) - return true; - - return !cors_flag_ && GetSecurityOrigin()->CanRequest(url); -} - -const SecurityOrigin* DocumentThreadableLoader::GetSecurityOrigin() const { - return security_origin_ - ? security_origin_.get() - : loading_context_->GetFetchContext()->GetSecurityOrigin(); -} - -Document* DocumentThreadableLoader::GetDocument() const { - ExecutionContext* context = GetExecutionContext(); - if (context->IsDocument()) - return ToDocument(context); - return nullptr; -} - -ExecutionContext* DocumentThreadableLoader::GetExecutionContext() const { - DCHECK(loading_context_); - return loading_context_->GetExecutionContext(); -} - -void DocumentThreadableLoader::Trace(blink::Visitor* visitor) { - visitor->Trace(loading_context_); - ThreadableLoader::Trace(visitor); - RawResourceClient::Trace(visitor); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/loader/document_threadable_loader.h b/third_party/blink/renderer/core/loader/document_threadable_loader.h deleted file mode 100644 index 2082201e..0000000 --- a/third_party/blink/renderer/core/loader/document_threadable_loader.h +++ /dev/null
@@ -1,244 +0,0 @@ -/* - * Copyright (C) 2009, 2012 Google Inc. All rights reserved. - * Copyright (C) 2013, Intel Corporation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_H_ - -#include <memory> -#include "services/network/public/mojom/fetch_api.mojom-blink.h" -#include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/core/loader/threadable_loader.h" -#include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h" -#include "third_party/blink/renderer/platform/network/http_header_map.h" -#include "third_party/blink/renderer/platform/timer.h" -#include "third_party/blink/renderer/platform/weborigin/referrer.h" -#include "third_party/blink/renderer/platform/wtf/forward.h" -#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" -#include "third_party/blink/renderer/platform/wtf/time.h" - -namespace blink { - -class Document; -class KURL; -class ResourceRequest; -class SecurityOrigin; -class ThreadableLoaderClient; -class ThreadableLoadingContext; - -// TODO(horo): We are using this class not only in documents, but also in -// workers. We should change the name to ThreadableLoaderImpl. -class CORE_EXPORT DocumentThreadableLoader final : public ThreadableLoader, - private RawResourceClient { - USING_GARBAGE_COLLECTED_MIXIN(DocumentThreadableLoader); - - public: - static void LoadResourceSynchronously(ThreadableLoadingContext&, - const ResourceRequest&, - ThreadableLoaderClient&, - const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); - - // Exposed for testing. Code outside this class should not call this function. - static std::unique_ptr<ResourceRequest> - CreateAccessControlPreflightRequestForTesting(const ResourceRequest&); - - static DocumentThreadableLoader* Create(ThreadableLoadingContext&, - ThreadableLoaderClient*, - const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); - ~DocumentThreadableLoader() override; - - void Start(const ResourceRequest&) override; - - void OverrideTimeout(unsigned long timeout) override; - - void Cancel() override; - void Detach() override; - void SetDefersLoading(bool); - - // Exposed for thread-correctness DCHECKs in WorkerThreadableLoader. - ExecutionContext* GetExecutionContext() const; - - void Trace(blink::Visitor*) override; - - private: - class DetachedClient; - enum BlockingBehavior { kLoadSynchronously, kLoadAsynchronously }; - - static std::unique_ptr<ResourceRequest> CreateAccessControlPreflightRequest( - const ResourceRequest&, - const SecurityOrigin*); - - DocumentThreadableLoader(ThreadableLoadingContext&, - ThreadableLoaderClient*, - BlockingBehavior, - const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); - - void Clear(); - - // ResourceClient - void NotifyFinished(Resource*) override; - - String DebugName() const override { return "DocumentThreadableLoader"; } - - // RawResourceClient - void DataSent(Resource*, - unsigned long long bytes_sent, - unsigned long long total_bytes_to_be_sent) override; - void ResponseReceived(Resource*, - const ResourceResponse&, - std::unique_ptr<WebDataConsumerHandle>) override; - void SetSerializedCachedMetadata(Resource*, const char*, size_t) override; - void DataReceived(Resource*, const char* data, size_t data_length) override; - bool RedirectReceived(Resource*, - const ResourceRequest&, - const ResourceResponse&) override; - void RedirectBlocked() override; - void DataDownloaded(Resource*, int) override; - void DidReceiveResourceTiming(Resource*, const ResourceTimingInfo&) override; - void DidDownloadToBlob(Resource*, scoped_refptr<BlobDataHandle>) override; - - // Notify Inspector and log to console about resource response. Use this - // method if response is not going to be finished normally. - void ReportResponseReceived(unsigned long identifier, - const ResourceResponse&); - - void DidTimeout(TimerBase*); - // Calls the appropriate loading method according to policy and data about - // origin. Only for handling the initial load (including fallback after - // consulting ServiceWorker). - void DispatchInitialRequest(ResourceRequest&); - void MakeCrossOriginAccessRequest(const ResourceRequest&); - - // Loads m_fallbackRequestForServiceWorker. - void LoadFallbackRequestForServiceWorker(); - // Issues a CORS preflight. - void LoadPreflightRequest(const ResourceRequest&, - const ResourceLoaderOptions&); - // Loads actual_request_. - void LoadActualRequest(); - // Clears actual_request_ and reports access control check failure to - // m_client. - void HandlePreflightFailure(const KURL&, const String& error_description); - // Investigates the response for the preflight request. If successful, - // the actual request will be made later in NotifyFinished(). - void HandlePreflightResponse(const ResourceResponse&); - - void DispatchDidFailAccessControlCheck(const ResourceError&); - void DispatchDidFail(const ResourceError&); - - void PrepareCrossOriginRequest(ResourceRequest&) const; - - // This method modifies the ResourceRequest by calling - // SetAllowStoredCredentials() on it based on same-origin-ness and the - // credentials mode. - // - // This method configures the ResourceLoaderOptions so that the underlying - // ResourceFetcher doesn't perform some part of the CORS logic since this - // class performs it by itself. - void LoadRequest(ResourceRequest&, ResourceLoaderOptions); - bool IsAllowedRedirect(network::mojom::FetchRequestMode, const KURL&) const; - - const SecurityOrigin* GetSecurityOrigin() const; - - // Returns null if the loader is not associated with Document. - // TODO(kinuko): Remove dependency to document. - Document* GetDocument() const; - - ThreadableLoaderClient* client_; - Member<ThreadableLoadingContext> loading_context_; - - const ThreadableLoaderOptions options_; - // Some items may be overridden by m_forceDoNotAllowStoredCredentials and - // m_securityOrigin. In such a case, build a ResourceLoaderOptions with - // up-to-date values from them and this variable, and use it. - const ResourceLoaderOptions resource_loader_options_; - - // True when feature OutOfBlinkCORS is enabled (https://crbug.com/736308). - bool out_of_blink_cors_; - - // Corresponds to the CORS flag in the Fetch spec. - bool cors_flag_; - scoped_refptr<const SecurityOrigin> security_origin_; - - // Set to true when the response data is given to a data consumer handle. - bool is_using_data_consumer_handle_; - - const bool async_; - - // Holds the original request context (used for sanity checks). - WebURLRequest::RequestContext request_context_; - - // Saved so that we can use the original value for the modes in - // ResponseReceived() where |resource| might be a reused one (e.g. preloaded - // resource) which can have different modes. - network::mojom::FetchRequestMode fetch_request_mode_; - network::mojom::FetchCredentialsMode fetch_credentials_mode_; - - // Holds the original request for fallback in case the Service Worker - // does not respond. - ResourceRequest fallback_request_for_service_worker_; - - // Holds the original request and options for it during preflight request - // handling phase. - ResourceRequest actual_request_; - ResourceLoaderOptions actual_options_; - - // stores request headers in case of a cross-origin redirect. - HTTPHeaderMap request_headers_; - - TaskRunnerTimer<DocumentThreadableLoader> timeout_timer_; - TimeTicks request_started_; // Time an asynchronous fetch request is started - - // Max number of times that this DocumentThreadableLoader can follow - // cross-origin redirects. This is used to limit the number of redirects. But - // this value is not the max number of total redirects allowed, because - // same-origin redirects are not counted here. - int cors_redirect_limit_; - - network::mojom::FetchRedirectMode redirect_mode_; - - // Holds the referrer after a redirect response was received. This referrer is - // used to populate the HTTP Referer header when following the redirect. - bool override_referrer_; - Referrer referrer_after_redirect_; - - bool detached_ = false; - - RawResourceClientStateChecker checker_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_H_
diff --git a/third_party/blink/renderer/core/loader/document_threadable_loader_client.h b/third_party/blink/renderer/core/loader/document_threadable_loader_client.h deleted file mode 100644 index 9554ac3..0000000 --- a/third_party/blink/renderer/core/loader/document_threadable_loader_client.h +++ /dev/null
@@ -1,61 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_CLIENT_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_CLIENT_H_ - -#include "base/macros.h" -#include "third_party/blink/renderer/core/loader/threadable_loader_client.h" - -namespace blink { - -class KURL; -class ResourceResponse; - -class DocumentThreadableLoaderClient : public ThreadableLoaderClient { - USING_FAST_MALLOC(DocumentThreadableLoaderClient); - - public: - bool IsDocumentThreadableLoaderClient() final { return true; } - - virtual bool WillFollowRedirect(const KURL& new_url, - const ResourceResponse&) { - return true; - } - - protected: - DocumentThreadableLoaderClient() = default; - - DISALLOW_COPY_AND_ASSIGN(DocumentThreadableLoaderClient); -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_DOCUMENT_THREADABLE_LOADER_CLIENT_H_
diff --git a/third_party/blink/renderer/core/loader/document_threadable_loader_test.cc b/third_party/blink/renderer/core/loader/document_threadable_loader_test.cc deleted file mode 100644 index b0371724..0000000 --- a/third_party/blink/renderer/core/loader/document_threadable_loader_test.cc +++ /dev/null
@@ -1,92 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/core/loader/document_threadable_loader.h" - -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/public/platform/web_cors.h" -#include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" - -namespace blink { - -namespace { - -TEST(DocumentThreadableLoaderCreatePreflightRequestTest, LexicographicalOrder) { - ResourceRequest request; - request.AddHTTPHeaderField("Orange", "Orange"); - request.AddHTTPHeaderField("Apple", "Red"); - request.AddHTTPHeaderField("Kiwifruit", "Green"); - request.AddHTTPHeaderField("Content-Type", "application/octet-stream"); - request.AddHTTPHeaderField("Strawberry", "Red"); - - std::unique_ptr<ResourceRequest> preflight = - DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting( - request); - - EXPECT_EQ("apple,content-type,kiwifruit,orange,strawberry", - preflight->HttpHeaderField("Access-Control-Request-Headers")); -} - -TEST(DocumentThreadableLoaderCreatePreflightRequestTest, ExcludeSimpleHeaders) { - ResourceRequest request; - request.AddHTTPHeaderField("Accept", "everything"); - request.AddHTTPHeaderField("Accept-Language", "everything"); - request.AddHTTPHeaderField("Content-Language", "everything"); - request.AddHTTPHeaderField("Save-Data", "on"); - - std::unique_ptr<ResourceRequest> preflight = - DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting( - request); - - // Do not emit empty-valued headers; an empty list of non-"CORS safelisted" - // request headers should cause "Access-Control-Request-Headers:" to be - // left out in the preflight request. - EXPECT_EQ(g_null_atom, - preflight->HttpHeaderField("Access-Control-Request-Headers")); -} - -TEST(DocumentThreadableLoaderCreatePreflightRequestTest, - ExcludeSimpleContentTypeHeader) { - ResourceRequest request; - request.AddHTTPHeaderField("Content-Type", "text/plain"); - - std::unique_ptr<ResourceRequest> preflight = - DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting( - request); - - // Empty list also; see comment in test above. - EXPECT_EQ(g_null_atom, - preflight->HttpHeaderField("Access-Control-Request-Headers")); -} - -TEST(DocumentThreadableLoaderCreatePreflightRequestTest, - IncludeNonSimpleHeader) { - ResourceRequest request; - request.AddHTTPHeaderField("X-Custom-Header", "foobar"); - - std::unique_ptr<ResourceRequest> preflight = - DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting( - request); - - EXPECT_EQ("x-custom-header", - preflight->HttpHeaderField("Access-Control-Request-Headers")); -} - -TEST(DocumentThreadableLoaderCreatePreflightRequestTest, - IncludeNonSimpleContentTypeHeader) { - ResourceRequest request; - request.AddHTTPHeaderField("Content-Type", "application/octet-stream"); - - std::unique_ptr<ResourceRequest> preflight = - DocumentThreadableLoader::CreateAccessControlPreflightRequestForTesting( - request); - - EXPECT_EQ("content-type", - preflight->HttpHeaderField("Access-Control-Request-Headers")); -} - -} // namespace - -} // namespace blink
diff --git a/third_party/blink/renderer/core/loader/interactive_detector.h b/third_party/blink/renderer/core/loader/interactive_detector.h index 0e62b777..1e77889 100644 --- a/third_party/blink/renderer/core/loader/interactive_detector.h +++ b/third_party/blink/renderer/core/loader/interactive_detector.h
@@ -10,10 +10,10 @@ #include "base/time/time.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/loader/long_task_detector.h" #include "third_party/blink/renderer/core/page/page_visibility_state.h" #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h" #include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/long_task_detector.h" #include "third_party/blink/renderer/platform/pod_interval.h" #include "third_party/blink/renderer/platform/supplementable.h" #include "third_party/blink/renderer/platform/timer.h"
diff --git a/third_party/blink/renderer/platform/long_task_detector.cc b/third_party/blink/renderer/core/loader/long_task_detector.cc similarity index 95% rename from third_party/blink/renderer/platform/long_task_detector.cc rename to third_party/blink/renderer/core/loader/long_task_detector.cc index c4b1dc8..fef8b5a 100644 --- a/third_party/blink/renderer/platform/long_task_detector.cc +++ b/third_party/blink/renderer/core/loader/long_task_detector.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 "third_party/blink/renderer/platform/long_task_detector.h" +#include "third_party/blink/renderer/core/loader/long_task_detector.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_thread.h"
diff --git a/third_party/blink/renderer/platform/long_task_detector.h b/third_party/blink/renderer/core/loader/long_task_detector.h similarity index 76% rename from third_party/blink/renderer/platform/long_task_detector.h rename to third_party/blink/renderer/core/loader/long_task_detector.h index 8c0a19ac..41076c7a 100644 --- a/third_party/blink/renderer/platform/long_task_detector.h +++ b/third_party/blink/renderer/core/loader/long_task_detector.h
@@ -2,19 +2,19 @@ // 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_LONG_TASK_DETECTOR_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LONG_TASK_DETECTOR_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LONG_TASK_DETECTOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LONG_TASK_DETECTOR_H_ +#include "base/macros.h" #include "base/task/sequence_manager/task_time_observer.h" #include "third_party/blink/public/platform/web_thread.h" +#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/platform_export.h" -#include "third_party/blink/renderer/platform/wtf/noncopyable.h" #include "third_party/blink/renderer/platform/wtf/time.h" namespace blink { -class PLATFORM_EXPORT LongTaskObserver : public GarbageCollectedMixin { +class CORE_EXPORT LongTaskObserver : public GarbageCollectedMixin { public: virtual ~LongTaskObserver() = default; @@ -26,11 +26,9 @@ // TaskTimeObserver on the main thread and observes every task. When the number // of LongTaskObservers drop to zero it automatically removes itself as a // TaskTimeObserver. -class PLATFORM_EXPORT LongTaskDetector final +class CORE_EXPORT LongTaskDetector final : public GarbageCollectedFinalized<LongTaskDetector>, public base::sequence_manager::TaskTimeObserver { - WTF_MAKE_NONCOPYABLE(LongTaskDetector); - public: static LongTaskDetector& Instance(); @@ -51,8 +49,10 @@ base::TimeTicks end_time) override; HeapHashSet<Member<LongTaskObserver>> observers_; + + DISALLOW_COPY_AND_ASSIGN(LongTaskDetector); }; } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_LONG_TASK_DETECTOR_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_LONG_TASK_DETECTOR_H_
diff --git a/third_party/blink/renderer/platform/long_task_detector_test.cc b/third_party/blink/renderer/core/loader/long_task_detector_test.cc similarity index 98% rename from third_party/blink/renderer/platform/long_task_detector_test.cc rename to third_party/blink/renderer/core/loader/long_task_detector_test.cc index bae1d36..4e95f720 100644 --- a/third_party/blink/renderer/platform/long_task_detector_test.cc +++ b/third_party/blink/renderer/core/loader/long_task_detector_test.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 "third_party/blink/renderer/platform/long_task_detector.h" +#include "third_party/blink/renderer/core/loader/long_task_detector.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/platform/cross_thread_functional.h"
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.cc b/third_party/blink/renderer/core/loader/threadable_loader.cc index 44b688f..9d94425 100644 --- a/third_party/blink/renderer/core/loader/threadable_loader.cc +++ b/third_party/blink/renderer/core/loader/threadable_loader.cc
@@ -1,5 +1,6 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2011, 2012 Google Inc. All rights reserved. + * Copyright (C) 2013, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -30,35 +31,1213 @@ #include "third_party/blink/renderer/core/loader/threadable_loader.h" -#include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/loader/document_threadable_loader.h" +#include <memory> +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "services/network/public/cpp/cors/cors_error_status.h" +#include "services/network/public/mojom/cors.mojom-blink.h" +#include "services/network/public/mojom/fetch_api.mojom-blink.h" +#include "third_party/blink/public/common/service_worker/service_worker_utils.h" +#include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/public/platform/task_type.h" +#include "third_party/blink/public/platform/web_cors.h" +#include "third_party/blink/public/platform/web_security_origin.h" +#include "third_party/blink/public/platform/web_url_request.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/frame/frame_console.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/core/frame/local_frame_client.h" +#include "third_party/blink/renderer/core/frame/web_feature.h" +#include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/core/inspector/inspector_network_agent.h" +#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h" +#include "third_party/blink/renderer/core/loader/base_fetch_context.h" +#include "third_party/blink/renderer/core/loader/frame_loader.h" +#include "third_party/blink/renderer/core/loader/threadable_loader_client.h" #include "third_party/blink/renderer/core/loader/threadable_loading_context.h" -#include "third_party/blink/renderer/core/workers/worker_global_scope.h" +#include "third_party/blink/renderer/core/probe/core_probes.h" +#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h" +#include "third_party/blink/renderer/platform/heap/self_keep_alive.h" +#include "third_party/blink/renderer/platform/loader/cors/cors.h" +#include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h" +#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h" +#include "third_party/blink/renderer/platform/shared_buffer.h" +#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" +#include "third_party/blink/renderer/platform/weborigin/security_policy.h" +#include "third_party/blink/renderer/platform/wtf/assertions.h" namespace blink { -ThreadableLoader* ThreadableLoader::Create( - ExecutionContext& context, - ThreadableLoaderClient* client, - const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resource_loader_options) { - DCHECK(client); - if (context.IsWorkerGlobalScope()) - ToWorkerGlobalScope(&context)->EnsureFetcher(); - return DocumentThreadableLoader::Create( - *ThreadableLoadingContext::Create(context), client, options, - resource_loader_options); +namespace { + +// Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch-0 +AtomicString CreateAccessControlRequestHeadersHeader( + const HTTPHeaderMap& headers) { + Vector<String> filtered_headers; + for (const auto& header : headers) { + // Exclude CORS-safelisted headers. + if (CORS::IsCORSSafelistedHeader(header.key, header.value)) + continue; + // Calling a deprecated function, but eventually this function, + // |CreateAccessControlRequestHeadersHeader| will be removed. + // When the request is from a Worker, referrer header was added by + // WorkerThreadableLoader. But it should not be added to + // Access-Control-Request-Headers header. + if (DeprecatedEqualIgnoringCase(header.key, "referer")) + continue; + filtered_headers.push_back(header.key.DeprecatedLower()); + } + if (!filtered_headers.size()) + return g_null_atom; + + // Sort header names lexicographically. + std::sort(filtered_headers.begin(), filtered_headers.end(), + WTF::CodePointCompareLessThan); + StringBuilder header_buffer; + for (const String& header : filtered_headers) { + if (!header_buffer.IsEmpty()) + header_buffer.Append(","); + header_buffer.Append(header); + } + + return header_buffer.ToAtomicString(); } +class EmptyDataHandle final : public WebDataConsumerHandle { + private: + class EmptyDataReader final : public WebDataConsumerHandle::Reader { + public: + explicit EmptyDataReader( + WebDataConsumerHandle::Client* client, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : factory_(this) { + task_runner->PostTask( + FROM_HERE, WTF::Bind(&EmptyDataReader::Notify, factory_.GetWeakPtr(), + WTF::Unretained(client))); + } + + private: + Result BeginRead(const void** buffer, + WebDataConsumerHandle::Flags, + size_t* available) override { + *available = 0; + *buffer = nullptr; + return kDone; + } + Result EndRead(size_t) override { + return WebDataConsumerHandle::kUnexpectedError; + } + void Notify(WebDataConsumerHandle::Client* client) { + client->DidGetReadable(); + } + base::WeakPtrFactory<EmptyDataReader> factory_; + }; + + std::unique_ptr<Reader> ObtainReader( + Client* client, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) override { + return std::make_unique<EmptyDataReader>(client, std::move(task_runner)); + } + const char* DebugName() const override { return "EmptyDataHandle"; } +}; + +} // namespace + +// DetachedClient is a ThreadableLoaderClient for a "detached" +// ThreadableLoader. It's for fetch requests with keepalive set, so +// it keeps itself alive during loading. +class ThreadableLoader::DetachedClient final + : public GarbageCollectedFinalized<DetachedClient>, + public ThreadableLoaderClient { + public: + explicit DetachedClient(ThreadableLoader* loader) + : self_keep_alive_(this), loader_(loader) {} + ~DetachedClient() override {} + + void DidFinishLoading(unsigned long identifier) override { + self_keep_alive_.Clear(); + } + void DidFail(const ResourceError&) override { self_keep_alive_.Clear(); } + void DidFailRedirectCheck() override { self_keep_alive_.Clear(); } + void Trace(Visitor* visitor) { visitor->Trace(loader_); } + + private: + SelfKeepAlive<DetachedClient> self_keep_alive_; + // Keep it alive. + const Member<ThreadableLoader> loader_; +}; + +// Max number of CORS redirects handled in ThreadableLoader. Same number +// as net/url_request/url_request.cc, and same number as +// https://fetch.spec.whatwg.org/#concept-http-fetch, Step 4. +// FIXME: currently the number of redirects is counted and limited here and in +// net/url_request/url_request.cc separately. +static const int kMaxCORSRedirects = 20; + +// static void ThreadableLoader::LoadResourceSynchronously( ExecutionContext& context, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resource_loader_options) { - DocumentThreadableLoader::LoadResourceSynchronously( - *ThreadableLoadingContext::Create(context), request, client, options, - resource_loader_options); + (new ThreadableLoader(context, &client, kLoadSynchronously, options, + resource_loader_options)) + ->Start(request); +} + +// static +std::unique_ptr<ResourceRequest> +ThreadableLoader::CreateAccessControlPreflightRequest( + const ResourceRequest& request, + const SecurityOrigin* origin) { + const KURL& request_url = request.Url(); + + DCHECK(request_url.User().IsEmpty()); + DCHECK(request_url.Pass().IsEmpty()); + + std::unique_ptr<ResourceRequest> preflight_request = + std::make_unique<ResourceRequest>(request_url); + preflight_request->SetHTTPMethod(HTTPNames::OPTIONS); + preflight_request->SetHTTPHeaderField( + HTTPNames::Access_Control_Request_Method, request.HttpMethod()); + preflight_request->SetPriority(request.Priority()); + preflight_request->SetRequestContext(request.GetRequestContext()); + preflight_request->SetFetchCredentialsMode( + network::mojom::FetchCredentialsMode::kOmit); + preflight_request->SetSkipServiceWorker(true); + // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is + // closed and we stop storing the referrer string as a `Referer` header. + preflight_request->SetReferrerString(request.HttpReferrer()); + preflight_request->SetReferrerPolicy(request.GetReferrerPolicy()); + + if (request.IsExternalRequest()) { + preflight_request->SetHTTPHeaderField( + HTTPNames::Access_Control_Request_External, "true"); + } + + const AtomicString request_headers = + CreateAccessControlRequestHeadersHeader(request.HttpHeaderFields()); + if (request_headers != g_null_atom) { + preflight_request->SetHTTPHeaderField( + HTTPNames::Access_Control_Request_Headers, request_headers); + } + + if (origin) + preflight_request->SetHTTPOrigin(origin); + + return preflight_request; +} + +// static +std::unique_ptr<ResourceRequest> +ThreadableLoader::CreateAccessControlPreflightRequestForTesting( + const ResourceRequest& request) { + return CreateAccessControlPreflightRequest(request, nullptr); +} + +// static +ThreadableLoader* ThreadableLoader::Create( + ExecutionContext& context, + ThreadableLoaderClient* client, + const ThreadableLoaderOptions& options, + const ResourceLoaderOptions& resource_loader_options) { + return new ThreadableLoader(context, client, kLoadAsynchronously, options, + resource_loader_options); +} + +ThreadableLoader::ThreadableLoader( + ExecutionContext& context, + ThreadableLoaderClient* client, + BlockingBehavior blocking_behavior, + const ThreadableLoaderOptions& options, + const ResourceLoaderOptions& resource_loader_options) + : client_(client), + loading_context_(ThreadableLoadingContext::Create(context)), + options_(options), + resource_loader_options_(resource_loader_options), + out_of_blink_cors_(RuntimeEnabledFeatures::OutOfBlinkCORSEnabled()), + cors_flag_(false), + security_origin_(resource_loader_options_.security_origin), + is_using_data_consumer_handle_(false), + async_(blocking_behavior == kLoadAsynchronously), + request_context_(WebURLRequest::kRequestContextUnspecified), + fetch_request_mode_(network::mojom::FetchRequestMode::kSameOrigin), + fetch_credentials_mode_(network::mojom::FetchCredentialsMode::kOmit), + timeout_timer_( + GetExecutionContext()->GetTaskRunner(TaskType::kNetworking), + this, + &ThreadableLoader::DidTimeout), + cors_redirect_limit_(0), + redirect_mode_(network::mojom::FetchRedirectMode::kFollow), + override_referrer_(false) { + DCHECK(client); +} + +void ThreadableLoader::Start(const ResourceRequest& request) { + // Setting an outgoing referer is only supported in the async code path. + DCHECK(async_ || request.HttpReferrer().IsEmpty()); + + bool cors_enabled = + CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()); + + // kPreventPreflight can be used only when the CORS is enabled. + DCHECK(request.CORSPreflightPolicy() == + network::mojom::CORSPreflightPolicy::kConsiderPreflight || + cors_enabled); + + if (cors_enabled) + cors_redirect_limit_ = kMaxCORSRedirects; + + request_context_ = request.GetRequestContext(); + fetch_request_mode_ = request.GetFetchRequestMode(); + fetch_credentials_mode_ = request.GetFetchCredentialsMode(); + redirect_mode_ = request.GetFetchRedirectMode(); + + if (request.GetFetchRequestMode() == + network::mojom::FetchRequestMode::kNoCORS) { + SECURITY_CHECK(WebCORS::IsNoCORSAllowedContext(request_context_)); + } else { + cors_flag_ = !GetSecurityOrigin()->CanRequest(request.Url()); + } + + // The CORS flag variable is not yet used at the step in the spec that + // corresponds to this line, but divert |cors_flag_| here for convenience. + if (cors_flag_ && request.GetFetchRequestMode() == + network::mojom::FetchRequestMode::kSameOrigin) { + ThreadableLoaderClient* client = client_; + Clear(); + ResourceError error = ResourceError::CancelledDueToAccessCheckError( + request.Url(), ResourceRequestBlockedReason::kOther, + CORS::GetErrorString( + CORS::ErrorParameter::CreateForDisallowedByMode(request.Url()))); + GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create( + kJSMessageSource, kErrorMessageLevel, error.LocalizedDescription())); + client->DidFail(error); + return; + } + + request_started_ = CurrentTimeTicks(); + + // Save any headers on the request here. If this request redirects + // cross-origin, we cancel the old request create a new one, and copy these + // headers. + request_headers_ = request.HttpHeaderFields(); + + ResourceRequest new_request(request); + + // Set the service worker mode to none if "bypass for network" in DevTools is + // enabled. + bool should_bypass_service_worker = false; + probe::shouldBypassServiceWorker(GetExecutionContext(), + &should_bypass_service_worker); + if (should_bypass_service_worker) + new_request.SetSkipServiceWorker(true); + + // In S13nServiceWorker, if the controller service worker has no fetch event + // handler, it's skipped entirely, so we should treat that case the same as + // having no controller. In non-S13nServiceWorker, we can't do that since we + // don't know which service worker will handle the request since it's + // determined on the browser process and skipWaiting() can happen in the + // meantime. + // + // TODO(crbug.com/715640): When non-S13nServiceWorker is removed, + // is_controlled_by_service_worker is the same as + // ControllerServiceWorkerMode::kControlled, so this code can be simplified. + bool is_controlled_by_service_worker = false; + switch ( + loading_context_->GetResourceFetcher()->IsControlledByServiceWorker()) { + case blink::mojom::ControllerServiceWorkerMode::kControlled: + is_controlled_by_service_worker = true; + break; + case blink::mojom::ControllerServiceWorkerMode::kNoFetchEventHandler: + if (ServiceWorkerUtils::IsServicificationEnabled()) + is_controlled_by_service_worker = false; + else + is_controlled_by_service_worker = true; + break; + case blink::mojom::ControllerServiceWorkerMode::kNoController: + is_controlled_by_service_worker = false; + break; + } + + // Process the CORS protocol inside the ThreadableLoader for the + // following cases: + // + // - When the request is sync or the protocol is unsupported since we can + // assume that any service worker (SW) is skipped for such requests by + // content/ code. + // - When |skip_service_worker| is true, any SW will be skipped. + // - If we're not yet controlled by a SW, then we're sure that this + // request won't be intercepted by a SW. In case we end up with + // sending a CORS preflight request, the actual request to be sent later + // may be intercepted. This is taken care of in LoadPreflightRequest() by + // setting |skip_service_worker| to true. + // + // From the above analysis, you can see that the request can never be + // intercepted by a SW inside this if-block. It's because: + // - |skip_service_worker| needs to be false, and + // - we're controlled by a SW at this point + // to allow a SW to intercept the request. Even when the request gets issued + // asynchronously after performing the CORS preflight, it doesn't get + // intercepted since LoadPreflightRequest() sets the flag to kNone in advance. + if (!async_ || new_request.GetSkipServiceWorker() || + !SchemeRegistry::ShouldTreatURLSchemeAsAllowingServiceWorkers( + new_request.Url().Protocol()) || + !is_controlled_by_service_worker) { + DispatchInitialRequest(new_request); + return; + } + + if (CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode())) { + // Save the request to fallback_request_for_service_worker to use when the + // service worker doesn't handle (call respondWith()) a CORS enabled + // request. + fallback_request_for_service_worker_ = ResourceRequest(request); + // Skip the service worker for the fallback request. + fallback_request_for_service_worker_.SetSkipServiceWorker(true); + } + + LoadRequest(new_request, resource_loader_options_); +} + +void ThreadableLoader::DispatchInitialRequest(ResourceRequest& request) { + if (out_of_blink_cors_ || (!request.IsExternalRequest() && !cors_flag_)) { + LoadRequest(request, resource_loader_options_); + return; + } + + DCHECK(CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()) || + request.IsExternalRequest()); + + MakeCrossOriginAccessRequest(request); +} + +void ThreadableLoader::PrepareCrossOriginRequest( + ResourceRequest& request) const { + if (GetSecurityOrigin()) + request.SetHTTPOrigin(GetSecurityOrigin()); + + // TODO(domfarolino): Stop setting the HTTPReferrer header, and instead use + // ResourceRequest::referrer_. See https://crbug.com/850813. + if (override_referrer_) + request.SetHTTPReferrer(referrer_after_redirect_); +} + +void ThreadableLoader::LoadPreflightRequest( + const ResourceRequest& actual_request, + const ResourceLoaderOptions& actual_options) { + std::unique_ptr<ResourceRequest> preflight_request = + CreateAccessControlPreflightRequest(actual_request, GetSecurityOrigin()); + + actual_request_ = actual_request; + actual_options_ = actual_options; + + // Explicitly set |skip_service_worker| to true here. Although the page is + // not controlled by a SW at this point, a new SW may be controlling the + // page when this actual request gets sent later. We should not send the + // actual request to the SW. See https://crbug.com/604583. + actual_request_.SetSkipServiceWorker(true); + + // Create a ResourceLoaderOptions for preflight. + ResourceLoaderOptions preflight_options = actual_options; + + LoadRequest(*preflight_request, preflight_options); +} + +void ThreadableLoader::MakeCrossOriginAccessRequest( + const ResourceRequest& request) { + DCHECK(CORS::IsCORSEnabledRequestMode(request.GetFetchRequestMode()) || + request.IsExternalRequest()); + DCHECK(client_); + DCHECK(!GetResource()); + + // Cross-origin requests are only allowed certain registered schemes. We would + // catch this when checking response headers later, but there is no reason to + // send a request, preflighted or not, that's guaranteed to be denied. + if (!SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled( + request.Url().Protocol())) { + DispatchDidFailAccessControlCheck( + ResourceError::CancelledDueToAccessCheckError( + request.Url(), ResourceRequestBlockedReason::kOther, + String::Format( + "Cross origin requests are only supported for protocol " + "schemes: %s.", + SchemeRegistry::ListOfCORSEnabledURLSchemes().Ascii().data()))); + return; + } + + // Non-secure origins may not make "external requests": + // https://wicg.github.io/cors-rfc1918/#integration-fetch + String error_message; + if (!GetExecutionContext()->IsSecureContext(error_message) && + request.IsExternalRequest()) { + DispatchDidFailAccessControlCheck( + ResourceError::CancelledDueToAccessCheckError( + request.Url(), ResourceRequestBlockedReason::kOrigin, + "Requests to internal network resources are not allowed " + "from non-secure contexts (see https://goo.gl/Y0ZkNV). " + "This is an experimental restriction which is part of " + "'https://mikewest.github.io/cors-rfc1918/'.")); + return; + } + + ResourceRequest cross_origin_request(request); + ResourceLoaderOptions cross_origin_options(resource_loader_options_); + + cross_origin_request.RemoveUserAndPassFromURL(); + + // Enforce the CORS preflight for checking the Access-Control-Allow-External + // header. The CORS preflight cache doesn't help for this purpose. + if (request.IsExternalRequest()) { + LoadPreflightRequest(cross_origin_request, cross_origin_options); + return; + } + + if (request.GetFetchRequestMode() != + network::mojom::FetchRequestMode::kCORSWithForcedPreflight) { + if (request.CORSPreflightPolicy() == + network::mojom::CORSPreflightPolicy::kPreventPreflight) { + PrepareCrossOriginRequest(cross_origin_request); + LoadRequest(cross_origin_request, cross_origin_options); + return; + } + + DCHECK_EQ(request.CORSPreflightPolicy(), + network::mojom::CORSPreflightPolicy::kConsiderPreflight); + + // We use ContainsOnlyCORSSafelistedOrForbiddenHeaders() here since + // |request| may have been modified in the process of loading (not from + // the user's input). For example, referrer. We need to accept them. For + // security, we must reject forbidden headers/methods at the point we + // accept user's input. Not here. + if (CORS::IsCORSSafelistedMethod(request.HttpMethod()) && + CORS::ContainsOnlyCORSSafelistedOrForbiddenHeaders( + request.HttpHeaderFields())) { + PrepareCrossOriginRequest(cross_origin_request); + LoadRequest(cross_origin_request, cross_origin_options); + return; + } + } + + // Now, we need to check that the request passes the CORS preflight either by + // issuing a CORS preflight or based on an entry in the CORS preflight cache. + + bool should_ignore_preflight_cache = false; + // Prevent use of the CORS preflight cache when instructed by the DevTools + // not to use caches. + probe::shouldForceCORSPreflight(GetExecutionContext(), + &should_ignore_preflight_cache); + if (should_ignore_preflight_cache || + !CORS::CheckIfRequestCanSkipPreflight( + GetSecurityOrigin()->ToString(), cross_origin_request.Url(), + cross_origin_request.GetFetchCredentialsMode(), + cross_origin_request.HttpMethod(), + cross_origin_request.HttpHeaderFields())) { + LoadPreflightRequest(cross_origin_request, cross_origin_options); + return; + } + + // We don't want any requests that could involve a CORS preflight to get + // intercepted by a foreign SW, even if we have the result of the preflight + // cached already. See https://crbug.com/674370. + cross_origin_request.SetSkipServiceWorker(true); + + PrepareCrossOriginRequest(cross_origin_request); + LoadRequest(cross_origin_request, cross_origin_options); +} + +ThreadableLoader::~ThreadableLoader() { + // |client_| is a raw pointer and having a non-null |client_| here probably + // means UaF. + // In the detached case, |this| is held by DetachedClient defined above, but + // SelfKeepAlive in DetachedClient is forcibly cancelled on worker thread + // termination. We can safely ignore this case. + CHECK(!client_ || detached_); + DCHECK(!GetResource()); +} + +void ThreadableLoader::OverrideTimeout(unsigned long timeout_milliseconds) { + DCHECK(async_); + + // |m_requestStartedSeconds| == 0.0 indicates loading is already finished and + // |m_timeoutTimer| is already stopped, and thus we do nothing for such cases. + // See https://crbug.com/551663 for details. + if (request_started_ <= TimeTicks()) + return; + + timeout_timer_.Stop(); + // At the time of this method's implementation, it is only ever called by + // XMLHttpRequest, when the timeout attribute is set after sending the + // request. + // + // The XHR request says to resolve the time relative to when the request + // was initially sent, however other uses of this method may need to + // behave differently, in which case this should be re-arranged somehow. + if (timeout_milliseconds) { + TimeDelta elapsed_time = CurrentTimeTicks() - request_started_; + TimeDelta next_fire = TimeDelta::FromMilliseconds(timeout_milliseconds); + TimeDelta resolved_time = std::max(next_fire - elapsed_time, TimeDelta()); + timeout_timer_.StartOneShot(resolved_time, FROM_HERE); + } +} + +void ThreadableLoader::Cancel() { + // Cancel can re-enter, and therefore |resource()| might be null here as a + // result. + if (!client_ || !GetResource()) { + Clear(); + return; + } + + DispatchDidFail(ResourceError::CancelledError(GetResource()->Url())); +} + +void ThreadableLoader::Detach() { + Resource* resource = GetResource(); + if (!resource) + return; + detached_ = true; + client_ = new DetachedClient(this); +} + +void ThreadableLoader::SetDefersLoading(bool value) { + if (GetResource() && GetResource()->Loader()) + GetResource()->Loader()->SetDefersLoading(value); +} + +void ThreadableLoader::Clear() { + client_ = nullptr; + timeout_timer_.Stop(); + request_started_ = TimeTicks(); + if (GetResource()) + checker_.WillRemoveClient(); + ClearResource(); +} + +// In this method, we can clear |request| to tell content::WebURLLoaderImpl of +// Chromium not to follow the redirect. This works only when this method is +// called by RawResource::willSendRequest(). If called by +// RawResource::didAddClient(), clearing |request| won't be propagated to +// content::WebURLLoaderImpl. So, this loader must also get detached from the +// resource by calling clearResource(). +// TODO(toyoshim): Implement OOR-CORS mode specific redirect code. +bool ThreadableLoader::RedirectReceived( + Resource* resource, + const ResourceRequest& new_request, + const ResourceResponse& redirect_response) { + DCHECK(client_); + DCHECK_EQ(resource, GetResource()); + + checker_.RedirectReceived(); + + const KURL& new_url = new_request.Url(); + const KURL& original_url = redirect_response.Url(); + + if (!actual_request_.IsNull()) { + DCHECK(!out_of_blink_cors_); + ReportResponseReceived(resource->Identifier(), redirect_response); + + HandlePreflightFailure( + original_url, CORS::GetErrorString( + CORS::ErrorParameter::CreateForDisallowedRedirect())); + + return false; + } + + if (redirect_mode_ == network::mojom::FetchRedirectMode::kManual) { + // We use |redirect_mode_| to check the original redirect mode. + // |new_request| is a new request for redirect. So we don't set the + // redirect mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect(). + DCHECK(new_request.UseStreamOnResponse()); + // There is no need to read the body of redirect response because there is + // no way to read the body of opaque-redirect filtered response's internal + // response. + // TODO(horo): If we support any API which expose the internal body, we will + // have to read the body. And also HTTPCache changes will be needed because + // it doesn't store the body of redirect responses. + ResponseReceived(resource, redirect_response, + std::make_unique<EmptyDataHandle>()); + + if (client_) { + DCHECK(actual_request_.IsNull()); + NotifyFinished(resource); + } + + return false; + } + + if (redirect_mode_ == network::mojom::FetchRedirectMode::kError) { + ThreadableLoaderClient* client = client_; + Clear(); + client->DidFailRedirectCheck(); + + return false; + } + + if (out_of_blink_cors_) { + client_->DidReceiveRedirectTo(new_url); + return client_->WillFollowRedirect(new_url, redirect_response); + } + + // Allow same origin requests to continue after allowing clients to audit the + // redirect. + if (IsAllowedRedirect(new_request.GetFetchRequestMode(), new_url)) { + client_->DidReceiveRedirectTo(new_url); + return client_->WillFollowRedirect(new_url, redirect_response); + } + + if (cors_redirect_limit_ <= 0) { + ThreadableLoaderClient* client = client_; + Clear(); + client->DidFailRedirectCheck(); + return false; + } + + --cors_redirect_limit_; + + probe::didReceiveCORSRedirectResponse( + GetExecutionContext(), resource->Identifier(), + GetDocument() && GetDocument()->GetFrame() + ? GetDocument()->GetFrame()->Loader().GetDocumentLoader() + : nullptr, + redirect_response, resource); + + base::Optional<network::mojom::CORSError> redirect_error = + CORS::CheckRedirectLocation(new_url); + if (redirect_error) { + DispatchDidFailAccessControlCheck( + ResourceError::CancelledDueToAccessCheckError( + original_url, ResourceRequestBlockedReason::kOther, + CORS::GetErrorString(CORS::ErrorParameter::CreateForRedirectCheck( + *redirect_error, original_url, new_url)))); + return false; + } + + if (cors_flag_) { + // The redirect response must pass the access control check if the CORS + // flag is set. + base::Optional<network::CORSErrorStatus> access_error = CORS::CheckAccess( + original_url, redirect_response.HttpStatusCode(), + redirect_response.HttpHeaderFields(), + new_request.GetFetchCredentialsMode(), *GetSecurityOrigin()); + if (access_error) { + DispatchDidFailAccessControlCheck( + ResourceError::CancelledDueToAccessCheckError( + original_url, ResourceRequestBlockedReason::kOther, + CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck( + *access_error, original_url, + redirect_response.HttpStatusCode(), *GetSecurityOrigin(), + request_context_, new_url)))); + return false; + } + } + + client_->DidReceiveRedirectTo(new_url); + + // FIXME: consider combining this with CORS redirect handling performed by + // CrossOriginAccessControl::handleRedirect(). + if (GetResource()) + checker_.WillRemoveClient(); + ClearResource(); + + // If + // - CORS flag is set, and + // - the origin of the redirect target URL is not same origin with the origin + // of the current request's URL + // set the source origin to a unique opaque origin. + // + // See https://fetch.spec.whatwg.org/#http-redirect-fetch. + if (cors_flag_) { + scoped_refptr<const SecurityOrigin> original_origin = + SecurityOrigin::Create(original_url); + scoped_refptr<const SecurityOrigin> new_origin = + SecurityOrigin::Create(new_url); + if (!original_origin->IsSameSchemeHostPort(new_origin.get())) + security_origin_ = SecurityOrigin::CreateUniqueOpaque(); + } + + // Set |cors_flag_| so that further logic (corresponds to the main fetch in + // the spec) will be performed with CORS flag set. + // See https://fetch.spec.whatwg.org/#http-redirect-fetch. + cors_flag_ = true; + + // Save the referrer to use when following the redirect. + override_referrer_ = true; + // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is + // closed and we stop storing the referrer string as a `Referer` header. + referrer_after_redirect_ = + Referrer(new_request.HttpReferrer(), new_request.GetReferrerPolicy()); + + ResourceRequest cross_origin_request(new_request); + + // Remove any headers that may have been added by the network layer that cause + // access control to fail. + cross_origin_request.ClearHTTPReferrer(); + cross_origin_request.ClearHTTPOrigin(); + cross_origin_request.ClearHTTPUserAgent(); + // Add any request headers which we previously saved from the + // original request. + for (const auto& header : request_headers_) + cross_origin_request.SetHTTPHeaderField(header.key, header.value); + MakeCrossOriginAccessRequest(cross_origin_request); + + return false; +} + +void ThreadableLoader::RedirectBlocked() { + checker_.RedirectBlocked(); + + // Tells the client that a redirect was received but not followed (for an + // unknown reason). + ThreadableLoaderClient* client = client_; + Clear(); + client->DidFailRedirectCheck(); +} + +void ThreadableLoader::DataSent(Resource* resource, + unsigned long long bytes_sent, + unsigned long long total_bytes_to_be_sent) { + DCHECK(client_); + DCHECK_EQ(resource, GetResource()); + DCHECK(async_); + + checker_.DataSent(); + client_->DidSendData(bytes_sent, total_bytes_to_be_sent); +} + +void ThreadableLoader::DataDownloaded(Resource* resource, int data_length) { + DCHECK(client_); + DCHECK_EQ(resource, GetResource()); + DCHECK(actual_request_.IsNull()); + + checker_.DataDownloaded(); + client_->DidDownloadData(data_length); +} + +void ThreadableLoader::DidReceiveResourceTiming( + Resource* resource, + const ResourceTimingInfo& info) { + DCHECK(client_); + DCHECK_EQ(resource, GetResource()); + + client_->DidReceiveResourceTiming(info); +} + +void ThreadableLoader::DidDownloadToBlob(Resource* resource, + scoped_refptr<BlobDataHandle> blob) { + DCHECK(client_); + DCHECK_EQ(resource, GetResource()); + + checker_.DidDownloadToBlob(); + client_->DidDownloadToBlob(std::move(blob)); +} + +void ThreadableLoader::HandlePreflightResponse( + const ResourceResponse& response) { + base::Optional<network::CORSErrorStatus> cors_error_status = + CORS::CheckPreflightAccess(response.Url(), response.HttpStatusCode(), + response.HttpHeaderFields(), + actual_request_.GetFetchCredentialsMode(), + *GetSecurityOrigin()); + if (cors_error_status) { + HandlePreflightFailure( + response.Url(), + CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck( + *cors_error_status, response.Url(), 0 /* status_code */, + *GetSecurityOrigin(), request_context_))); + return; + } + + base::Optional<network::mojom::CORSError> preflight_error = + CORS::CheckPreflight(response.HttpStatusCode()); + if (preflight_error) { + HandlePreflightFailure( + response.Url(), CORS::GetErrorString( + CORS::ErrorParameter::CreateForPreflightStatusCheck( + response.HttpStatusCode()))); + return; + } + + if (actual_request_.IsExternalRequest()) { + base::Optional<network::CORSErrorStatus> external_preflight_status = + CORS::CheckExternalPreflight(response.HttpHeaderFields()); + if (external_preflight_status) { + HandlePreflightFailure( + response.Url(), + CORS::GetErrorString( + CORS::ErrorParameter::CreateForExternalPreflightCheck( + *external_preflight_status))); + return; + } + } + + String access_control_error_description; + if (!CORS::EnsurePreflightResultAndCacheOnSuccess( + response.HttpHeaderFields(), GetSecurityOrigin()->ToString(), + actual_request_.Url(), actual_request_.HttpMethod(), + actual_request_.HttpHeaderFields(), + actual_request_.GetFetchCredentialsMode(), + &access_control_error_description)) { + HandlePreflightFailure(response.Url(), access_control_error_description); + } +} + +void ThreadableLoader::ReportResponseReceived( + unsigned long identifier, + const ResourceResponse& response) { + LocalFrame* frame = GetDocument() ? GetDocument()->GetFrame() : nullptr; + if (!frame) + return; + DocumentLoader* loader = frame->Loader().GetDocumentLoader(); + probe::didReceiveResourceResponse(GetExecutionContext(), identifier, loader, + response, GetResource()); + frame->Console().ReportResourceResponseReceived(loader, identifier, response); +} + +void ThreadableLoader::ResponseReceived( + Resource* resource, + const ResourceResponse& response, + std::unique_ptr<WebDataConsumerHandle> handle) { + DCHECK_EQ(resource, GetResource()); + DCHECK(client_); + + checker_.ResponseReceived(); + + if (handle) + is_using_data_consumer_handle_ = true; + + // TODO(toyoshim): Support OOR-CORS preflight and Service Worker case. + // Note that CORS-preflight is usually handled in the Network Service side, + // but still done in Blink side when it is needed on redirects. + // https://crbug.com/736308. + if (out_of_blink_cors_ && !response.WasFetchedViaServiceWorker()) { + DCHECK(actual_request_.IsNull()); + fallback_request_for_service_worker_ = ResourceRequest(); + client_->DidReceiveResponse(resource->Identifier(), response, + std::move(handle)); + return; + } + + // Code path for legacy Blink CORS. + if (!actual_request_.IsNull()) { + ReportResponseReceived(resource->Identifier(), response); + HandlePreflightResponse(response); + return; + } + + if (response.WasFetchedViaServiceWorker()) { + if (response.WasFallbackRequiredByServiceWorker()) { + // At this point we must have m_fallbackRequestForServiceWorker. (For + // SharedWorker the request won't be CORS or CORS-with-preflight, + // therefore fallback-to-network is handled in the browser process when + // the ServiceWorker does not call respondWith().) + DCHECK(!fallback_request_for_service_worker_.IsNull()); + ReportResponseReceived(resource->Identifier(), response); + LoadFallbackRequestForServiceWorker(); + return; + } + + // It's possible that we issue a fetch with request with non "no-cors" + // mode but get an opaque filtered response if a service worker is involved. + // We dispatch a CORS failure for the case. + // TODO(yhirano): This is probably not spec conformant. Fix it after + // https://github.com/w3c/preload/issues/100 is addressed. + if (fetch_request_mode_ != network::mojom::FetchRequestMode::kNoCORS && + response.ResponseTypeViaServiceWorker() == + network::mojom::FetchResponseType::kOpaque) { + DispatchDidFailAccessControlCheck( + ResourceError::CancelledDueToAccessCheckError( + response.Url(), ResourceRequestBlockedReason::kOther, + CORS::GetErrorString( + CORS::ErrorParameter::CreateForInvalidResponse( + response.Url(), *GetSecurityOrigin())))); + return; + } + + fallback_request_for_service_worker_ = ResourceRequest(); + client_->DidReceiveResponse(resource->Identifier(), response, + std::move(handle)); + return; + } + + // Even if the request met the conditions to get handled by a Service Worker + // in the constructor of this class (and therefore + // |m_fallbackRequestForServiceWorker| is set), the Service Worker may skip + // processing the request. Only if the request is same origin, the skipped + // response may come here (wasFetchedViaServiceWorker() returns false) since + // such a request doesn't have to go through the CORS algorithm by calling + // loadFallbackRequestForServiceWorker(). + DCHECK(fallback_request_for_service_worker_.IsNull() || + GetSecurityOrigin()->CanRequest( + fallback_request_for_service_worker_.Url())); + fallback_request_for_service_worker_ = ResourceRequest(); + + if (CORS::IsCORSEnabledRequestMode(fetch_request_mode_) && cors_flag_) { + base::Optional<network::CORSErrorStatus> access_error = CORS::CheckAccess( + response.Url(), response.HttpStatusCode(), response.HttpHeaderFields(), + fetch_credentials_mode_, *GetSecurityOrigin()); + if (access_error) { + ReportResponseReceived(resource->Identifier(), response); + DispatchDidFailAccessControlCheck( + ResourceError::CancelledDueToAccessCheckError( + response.Url(), ResourceRequestBlockedReason::kOther, + CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck( + *access_error, response.Url(), response.HttpStatusCode(), + *GetSecurityOrigin(), request_context_)))); + return; + } + } + + client_->DidReceiveResponse(resource->Identifier(), response, + std::move(handle)); +} + +void ThreadableLoader::SetSerializedCachedMetadata(Resource*, + const char* data, + size_t size) { + checker_.SetSerializedCachedMetadata(); + + if (!actual_request_.IsNull()) + return; + client_->DidReceiveCachedMetadata(data, size); +} + +void ThreadableLoader::DataReceived(Resource* resource, + const char* data, + size_t data_length) { + DCHECK_EQ(resource, GetResource()); + DCHECK(client_); + + checker_.DataReceived(); + + if (is_using_data_consumer_handle_) + return; + + // Preflight data should be invisible to clients. + if (!actual_request_.IsNull()) + return; + + DCHECK(fallback_request_for_service_worker_.IsNull()); + + // TODO(junov): Fix the ThreadableLoader ecosystem to use size_t. Until then, + // we use safeCast to trap potential overflows. + client_->DidReceiveData(data, SafeCast<unsigned>(data_length)); +} + +void ThreadableLoader::NotifyFinished(Resource* resource) { + DCHECK(client_); + DCHECK_EQ(resource, GetResource()); + + checker_.NotifyFinished(resource); + + // Don't throw an exception for failed sync local file loads. + // TODO(japhet): This logic has been moved around but unchanged since 2007. + // Tested by fast/xmlhttprequest/xmlhttprequest-missing-file-exception.html + // Do we still need this? + bool is_sync_to_local_file = resource->Url().IsLocalFile() && !async_; + + if (resource->ErrorOccurred() && !is_sync_to_local_file) { + DispatchDidFail(resource->GetResourceError()); + return; + } + + DCHECK(fallback_request_for_service_worker_.IsNull()); + + if (!actual_request_.IsNull()) { + DCHECK(actual_request_.IsExternalRequest() || cors_flag_); + LoadActualRequest(); + return; + } + + ThreadableLoaderClient* client = client_; + // Protect the resource in |didFinishLoading| in order not to release the + // downloaded file. + Persistent<Resource> protect = GetResource(); + Clear(); + client->DidFinishLoading(resource->Identifier()); +} + +void ThreadableLoader::DidTimeout(TimerBase* timer) { + DCHECK(async_); + DCHECK_EQ(timer, &timeout_timer_); + // clearResource() may be called in clear() and some other places. clear() + // calls stop() on |m_timeoutTimer|. In the other places, the resource is set + // again. If the creation fails, clear() is called. So, here, resource() is + // always non-nullptr. + DCHECK(GetResource()); + // When |m_client| is set to nullptr only in clear() where |m_timeoutTimer| + // is stopped. So, |m_client| is always non-nullptr here. + DCHECK(client_); + + DispatchDidFail(ResourceError::TimeoutError(GetResource()->Url())); +} + +void ThreadableLoader::LoadFallbackRequestForServiceWorker() { + if (GetResource()) + checker_.WillRemoveClient(); + ClearResource(); + ResourceRequest fallback_request(fallback_request_for_service_worker_); + fallback_request_for_service_worker_ = ResourceRequest(); + DispatchInitialRequest(fallback_request); +} + +void ThreadableLoader::LoadActualRequest() { + ResourceRequest actual_request = actual_request_; + ResourceLoaderOptions actual_options = actual_options_; + actual_request_ = ResourceRequest(); + actual_options_ = ResourceLoaderOptions(); + + if (GetResource()) + checker_.WillRemoveClient(); + ClearResource(); + + PrepareCrossOriginRequest(actual_request); + LoadRequest(actual_request, actual_options); +} + +void ThreadableLoader::HandlePreflightFailure(const KURL& url, + const String& error_description) { + // Prevent NotifyFinished() from bypassing access check. + actual_request_ = ResourceRequest(); + + DispatchDidFailAccessControlCheck( + ResourceError::CancelledDueToAccessCheckError( + url, ResourceRequestBlockedReason::kOther, error_description)); +} + +void ThreadableLoader::DispatchDidFailAccessControlCheck( + const ResourceError& error) { + const String message = "Failed to load " + error.FailingURL() + ": " + + error.LocalizedDescription(); + GetExecutionContext()->AddConsoleMessage( + ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel, message)); + + ThreadableLoaderClient* client = client_; + Clear(); + client->DidFail(error); +} + +void ThreadableLoader::DispatchDidFail(const ResourceError& error) { + if (error.CORSErrorStatus()) { + DCHECK(out_of_blink_cors_); + // TODO(toyoshim): Should consider to pass correct arguments instead of + // KURL(), and 0 to GetErrorString(). + // We still need plumbing some more information. + GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create( + kJSMessageSource, kErrorMessageLevel, + "Failed to load " + error.FailingURL() + ": " + + CORS::GetErrorString(CORS::ErrorParameter::Create( + *error.CORSErrorStatus(), + KURL(error.FailingURL()), KURL(), 0, + *GetSecurityOrigin(), request_context_)) + .Utf8() + .data())); + } + ThreadableLoaderClient* client = client_; + Clear(); + client->DidFail(error); +} + +void ThreadableLoader::LoadRequest( + ResourceRequest& request, + ResourceLoaderOptions resource_loader_options) { + resource_loader_options.cors_handling_by_resource_fetcher = + kDisableCORSHandlingByResourceFetcher; + + bool allow_stored_credentials = false; + switch (request.GetFetchCredentialsMode()) { + case network::mojom::FetchCredentialsMode::kOmit: + break; + case network::mojom::FetchCredentialsMode::kSameOrigin: + // TODO(toyoshim): It's wrong to use |cors_flag| here. Fix it to use the + // response tainting. + // + // TODO(toyoshim): The credentials mode must work even when the "no-cors" + // mode is in use. See the following issues: + // - https://github.com/whatwg/fetch/issues/130 + // - https://github.com/whatwg/fetch/issues/169 + allow_stored_credentials = !cors_flag_; + break; + case network::mojom::FetchCredentialsMode::kInclude: + allow_stored_credentials = true; + break; + } + request.SetAllowStoredCredentials(allow_stored_credentials); + + resource_loader_options.security_origin = security_origin_; + + if (!actual_request_.IsNull()) + resource_loader_options.data_buffering_policy = kBufferData; + + TimeDelta timeout = + TimeDelta::FromMilliseconds(options_.timeout_milliseconds); + if (options_.timeout_milliseconds > 0) { + if (!async_) { + request.SetTimeoutInterval(timeout); + } else if (!timeout_timer_.IsActive()) { + // The timer can be active if this is the actual request of a + // CORS-with-preflight request. + timeout_timer_.StartOneShot(timeout, FROM_HERE); + } + } + + FetchParameters new_params(request, resource_loader_options); + DCHECK(!GetResource()); + + checker_.WillAddClient(); + ResourceFetcher* fetcher = loading_context_->GetResourceFetcher(); + if (request.GetRequestContext() == WebURLRequest::kRequestContextVideo || + request.GetRequestContext() == WebURLRequest::kRequestContextAudio) { + DCHECK(async_); + RawResource::FetchMedia(new_params, fetcher, this); + } else if (request.GetRequestContext() == + WebURLRequest::kRequestContextManifest) { + DCHECK(async_); + RawResource::FetchManifest(new_params, fetcher, this); + } else if (async_) { + RawResource::Fetch(new_params, fetcher, this); + } else { + RawResource::FetchSynchronously(new_params, fetcher, this); + } +} + +bool ThreadableLoader::IsAllowedRedirect( + network::mojom::FetchRequestMode fetch_request_mode, + const KURL& url) const { + if (fetch_request_mode == network::mojom::FetchRequestMode::kNoCORS) + return true; + + return !cors_flag_ && GetSecurityOrigin()->CanRequest(url); +} + +const SecurityOrigin* ThreadableLoader::GetSecurityOrigin() const { + return security_origin_ + ? security_origin_.get() + : loading_context_->GetFetchContext()->GetSecurityOrigin(); +} + +Document* ThreadableLoader::GetDocument() const { + ExecutionContext* context = GetExecutionContext(); + if (context->IsDocument()) + return ToDocument(context); + return nullptr; +} + +ExecutionContext* ThreadableLoader::GetExecutionContext() const { + DCHECK(loading_context_); + return loading_context_->GetExecutionContext(); +} + +void ThreadableLoader::Trace(blink::Visitor* visitor) { + visitor->Trace(loading_context_); + RawResourceClient::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.h b/third_party/blink/renderer/core/loader/threadable_loader.h index c0f81603..e64dee1 100644 --- a/third_party/blink/renderer/core/loader/threadable_loader.h +++ b/third_party/blink/renderer/core/loader/threadable_loader.h
@@ -1,5 +1,6 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2009, 2012 Google Inc. All rights reserved. + * Copyright (C) 2013, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -34,52 +35,41 @@ #include <memory> #include "base/macros.h" +#include "services/network/public/mojom/fetch_api.mojom-blink.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/platform/cross_thread_copier.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h" +#include "third_party/blink/renderer/platform/network/http_header_map.h" +#include "third_party/blink/renderer/platform/timer.h" +#include "third_party/blink/renderer/platform/weborigin/referrer.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" +#include "third_party/blink/renderer/platform/wtf/forward.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +#include "third_party/blink/renderer/platform/wtf/time.h" namespace blink { -class ResourceRequest; class ExecutionContext; +class Document; +class KURL; +class ResourceRequest; +class SecurityOrigin; +class ThreadableLoadingContext; class ThreadableLoaderClient; +// TODO(japhet): This appears unnecessary. Just take a timout_milliseconds +// optional param in constructor? struct ThreadableLoaderOptions { DISALLOW_NEW(); ThreadableLoaderOptions() : timeout_milliseconds(0) {} - // When adding members, CrossThreadThreadableLoaderOptionsData should // be updated. - unsigned long timeout_milliseconds; }; -// Encode AtomicString as String to cross threads. -struct CrossThreadThreadableLoaderOptionsData { - STACK_ALLOCATED(); - explicit CrossThreadThreadableLoaderOptionsData( - const ThreadableLoaderOptions& options) - : timeout_milliseconds(options.timeout_milliseconds) {} - - operator ThreadableLoaderOptions() const { - ThreadableLoaderOptions options; - options.timeout_milliseconds = timeout_milliseconds; - return options; - } - - unsigned long timeout_milliseconds; -}; - -template <> -struct CrossThreadCopier<ThreadableLoaderOptions> { - typedef CrossThreadThreadableLoaderOptionsData Type; - static Type Copy(const ThreadableLoaderOptions& options) { - return CrossThreadThreadableLoaderOptionsData(options); - } -}; - // Useful for doing loader operations from any thread (not threadsafe, just able // to run on threads other than the main thread). // @@ -92,7 +82,10 @@ // that this ThreadableLoader creates. It can be altered e.g. when // redirect happens. class CORE_EXPORT ThreadableLoader - : public GarbageCollectedFinalized<ThreadableLoader> { + : public GarbageCollectedFinalized<ThreadableLoader>, + private RawResourceClient { + USING_GARBAGE_COLLECTED_MIXIN(ThreadableLoader); + public: static void LoadResourceSynchronously(ExecutionContext&, const ResourceRequest&, @@ -100,6 +93,10 @@ const ThreadableLoaderOptions&, const ResourceLoaderOptions&); + // Exposed for testing. Code outside this class should not call this function. + static std::unique_ptr<ResourceRequest> + CreateAccessControlPreflightRequestForTesting(const ResourceRequest&); + // This method never returns nullptr. // // This method must always be followed by start() call. @@ -136,9 +133,9 @@ const ThreadableLoaderOptions&, const ResourceLoaderOptions&); - // The methods on the ThreadableLoaderClient passed on create() call - // may be called synchronous to start() call. - virtual void Start(const ResourceRequest&) = 0; + ~ThreadableLoader() override; + + void Start(const ResourceRequest&); // A ThreadableLoader may have a timeout specified. It is possible, in some // cases, for the timeout to be overridden after the request is sent (for @@ -146,22 +143,166 @@ // // Set a new timeout relative to the time the request started, in // milliseconds. - virtual void OverrideTimeout(unsigned long timeout_milliseconds) = 0; + void OverrideTimeout(unsigned long timeout_milliseconds); - // Cancel the request. - virtual void Cancel() = 0; + void Cancel(); - // Detach the loader from the request. This function is for "keepalive" + // Detach the loader from the request. This ffunction is for "keepalive" // requests. No notification will be sent to the client, but the request // will be processed. - virtual void Detach() = 0; + void Detach(); - virtual ~ThreadableLoader() = default; + void SetDefersLoading(bool); - virtual void Trace(blink::Visitor* visitor) {} + void Trace(blink::Visitor* visitor) override; - protected: - ThreadableLoader() = default; + private: + class DetachedClient; + enum BlockingBehavior { kLoadSynchronously, kLoadAsynchronously }; + + ThreadableLoader(ExecutionContext&, + ThreadableLoaderClient*, + BlockingBehavior, + const ThreadableLoaderOptions&, + const ResourceLoaderOptions&); + + static std::unique_ptr<ResourceRequest> CreateAccessControlPreflightRequest( + const ResourceRequest&, + const SecurityOrigin*); + + void Clear(); + + // ResourceClient + void NotifyFinished(Resource*) override; + + String DebugName() const override { return "ThreadableLoader"; } + + // RawResourceClient + void DataSent(Resource*, + unsigned long long bytes_sent, + unsigned long long total_bytes_to_be_sent) override; + void ResponseReceived(Resource*, + const ResourceResponse&, + std::unique_ptr<WebDataConsumerHandle>) override; + void SetSerializedCachedMetadata(Resource*, const char*, size_t) override; + void DataReceived(Resource*, const char* data, size_t data_length) override; + bool RedirectReceived(Resource*, + const ResourceRequest&, + const ResourceResponse&) override; + void RedirectBlocked() override; + void DataDownloaded(Resource*, int) override; + void DidReceiveResourceTiming(Resource*, const ResourceTimingInfo&) override; + void DidDownloadToBlob(Resource*, scoped_refptr<BlobDataHandle>) override; + + // Notify Inspector and log to console about resource response. Use this + // method if response is not going to be finished normally. + void ReportResponseReceived(unsigned long identifier, + const ResourceResponse&); + + void DidTimeout(TimerBase*); + // Calls the appropriate loading method according to policy and data about + // origin. Only for handling the initial load (including fallback after + // consulting ServiceWorker). + void DispatchInitialRequest(ResourceRequest&); + void MakeCrossOriginAccessRequest(const ResourceRequest&); + + // Loads m_fallbackRequestForServiceWorker. + void LoadFallbackRequestForServiceWorker(); + // Issues a CORS preflight. + void LoadPreflightRequest(const ResourceRequest&, + const ResourceLoaderOptions&); + // Loads actual_request_. + void LoadActualRequest(); + // Clears actual_request_ and reports access control check failure to + // m_client. + void HandlePreflightFailure(const KURL&, const String& error_description); + // Investigates the response for the preflight request. If successful, + // the actual request will be made later in NotifyFinished(). + void HandlePreflightResponse(const ResourceResponse&); + + void DispatchDidFailAccessControlCheck(const ResourceError&); + void DispatchDidFail(const ResourceError&); + + void PrepareCrossOriginRequest(ResourceRequest&) const; + + // This method modifies the ResourceRequest by calling + // SetAllowStoredCredentials() on it based on same-origin-ness and the + // credentials mode. + // + // This method configures the ResourceLoaderOptions so that the underlying + // ResourceFetcher doesn't perform some part of the CORS logic since this + // class performs it by itself. + void LoadRequest(ResourceRequest&, ResourceLoaderOptions); + bool IsAllowedRedirect(network::mojom::FetchRequestMode, const KURL&) const; + + const SecurityOrigin* GetSecurityOrigin() const; + + // Returns null if the loader is not associated with Document. + // TODO(kinuko): Remove dependency to document. + Document* GetDocument() const; + ExecutionContext* GetExecutionContext() const; + + ThreadableLoaderClient* client_; + Member<ThreadableLoadingContext> loading_context_; + + const ThreadableLoaderOptions options_; + // Some items may be overridden by m_forceDoNotAllowStoredCredentials and + // m_securityOrigin. In such a case, build a ResourceLoaderOptions with + // up-to-date values from them and this variable, and use it. + const ResourceLoaderOptions resource_loader_options_; + + // True when feature OutOfBlinkCORS is enabled (https://crbug.com/736308). + bool out_of_blink_cors_; + + // Corresponds to the CORS flag in the Fetch spec. + bool cors_flag_; + scoped_refptr<const SecurityOrigin> security_origin_; + + // Set to true when the response data is given to a data consumer handle. + bool is_using_data_consumer_handle_; + + const bool async_; + + // Holds the original request context (used for sanity checks). + WebURLRequest::RequestContext request_context_; + + // Saved so that we can use the original value for the modes in + // ResponseReceived() where |resource| might be a reused one (e.g. preloaded + // resource) which can have different modes. + network::mojom::FetchRequestMode fetch_request_mode_; + network::mojom::FetchCredentialsMode fetch_credentials_mode_; + + // Holds the original request for fallback in case the Service Worker + // does not respond. + ResourceRequest fallback_request_for_service_worker_; + + // Holds the original request and options for it during preflight request + // handling phase. + ResourceRequest actual_request_; + ResourceLoaderOptions actual_options_; + + // stores request headers in case of a cross-origin redirect. + HTTPHeaderMap request_headers_; + + TaskRunnerTimer<ThreadableLoader> timeout_timer_; + TimeTicks request_started_; // Time an asynchronous fetch request is started + + // Max number of times that this ThreadableLoader can follow + // cross-origin redirects. This is used to limit the number of redirects. But + // this value is not the max number of total redirects allowed, because + // same-origin redirects are not counted here. + int cors_redirect_limit_; + + network::mojom::FetchRedirectMode redirect_mode_; + + // Holds the referrer after a redirect response was received. This referrer is + // used to populate the HTTP Referer header when following the redirect. + bool override_referrer_; + Referrer referrer_after_redirect_; + + bool detached_ = false; + + RawResourceClientStateChecker checker_; DISALLOW_COPY_AND_ASSIGN(ThreadableLoader); };
diff --git a/third_party/blink/renderer/core/loader/threadable_loader_client.h b/third_party/blink/renderer/core/loader/threadable_loader_client.h index ed55b27..a5404ed7 100644 --- a/third_party/blink/renderer/core/loader/threadable_loader_client.h +++ b/third_party/blink/renderer/core/loader/threadable_loader_client.h
@@ -50,7 +50,12 @@ public: virtual void DidSendData(unsigned long long /*bytesSent*/, unsigned long long /*totalBytesToBeSent*/) {} + // TODO(japhet?): Merge these redirect callbacks. virtual void DidReceiveRedirectTo(const KURL&) {} + virtual bool WillFollowRedirect(const KURL& new_url, + const ResourceResponse&) { + return true; + } virtual void DidReceiveResponse(unsigned long /*identifier*/, const ResourceResponse&, std::unique_ptr<WebDataConsumerHandle>) {} @@ -61,8 +66,6 @@ virtual void DidFailRedirectCheck() {} virtual void DidReceiveResourceTiming(const ResourceTimingInfo&) {} - virtual bool IsDocumentThreadableLoaderClient() { return false; } - virtual void DidDownloadData(int /*dataLength*/) {} // Called for requests that had DownloadToBlob set to true. Can be called with // null if creating the blob failed for some reason (but the download itself
diff --git a/third_party/blink/renderer/core/loader/threadable_loader_test.cc b/third_party/blink/renderer/core/loader/threadable_loader_test.cc index 0638411..07fc4f1 100644 --- a/third_party/blink/renderer/core/loader/threadable_loader_test.cc +++ b/third_party/blink/renderer/core/loader/threadable_loader_test.cc
@@ -17,11 +17,10 @@ #include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/public/platform/web_url_response.h" #include "third_party/blink/public/platform/web_worker_fetch_context.h" -#include "third_party/blink/renderer/core/loader/document_threadable_loader.h" +#include "third_party/blink/renderer/core/loader/threadable_loader.h" #include "third_party/blink/renderer/core/loader/threadable_loader_client.h" #include "third_party/blink/renderer/core/loader/threadable_loading_context.h" #include "third_party/blink/renderer/core/loader/worker_fetch_context.h" -#include "third_party/blink/renderer/core/loader/worker_threadable_loader.h" #include "third_party/blink/renderer/core/testing/dummy_page_holder.h" #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h" #include "third_party/blink/renderer/core/workers/worker_thread_test_helper.h" @@ -198,9 +197,8 @@ void CreateLoader(ThreadableLoaderClient* client) override { ThreadableLoaderOptions options; ResourceLoaderOptions resource_loader_options; - loader_ = DocumentThreadableLoader::Create( - *ThreadableLoadingContext::Create(GetDocument()), client, options, - resource_loader_options); + loader_ = ThreadableLoader::Create(GetDocument(), client, options, + resource_loader_options); } void StartLoader(const ResourceRequest& request) override { @@ -233,7 +231,7 @@ std::unique_ptr<DummyPageHolder> dummy_page_holder_; Checkpoint checkpoint_; - Persistent<DocumentThreadableLoader> loader_; + Persistent<ThreadableLoader> loader_; }; class WebWorkerFetchContextForTest : public WebWorkerFetchContext { @@ -394,10 +392,7 @@ ThreadableLoaderOptions options; ResourceLoaderOptions resource_loader_options; - // Ensure that WorkerThreadableLoader is created. - // ThreadableLoader::create() determines whether it should create - // a DocumentThreadableLoader or WorkerThreadableLoader based on - // isWorkerGlobalScope(). + // Ensure that ThreadableLoader is created. DCHECK(worker_thread_->GlobalScope()->IsWorkerGlobalScope()); loader_ = ThreadableLoader::Create(*worker_thread_->GlobalScope(), client, @@ -623,9 +618,7 @@ EXPECT_CALL(GetCheckpoint(), Call(2)); EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); EXPECT_CALL(*Client(), DidReceiveData(StrEq("fox"), 4)); - // We expect didReceiveResourceTiming() calls in DocumentThreadableLoader; - // it's used to connect DocumentThreadableLoader to WorkerThreadableLoader, - // not to ThreadableLoaderClient. + // We expect didReceiveResourceTiming() calls in ThreadableLoader. EXPECT_CALL(*Client(), DidReceiveResourceTiming(_)); EXPECT_CALL(*Client(), DidFinishLoading(_)); @@ -903,6 +896,74 @@ CallCheckpoint(2); } +TEST(ThreadableLoaderCreatePreflightRequestTest, LexicographicalOrder) { + ResourceRequest request; + request.AddHTTPHeaderField("Orange", "Orange"); + request.AddHTTPHeaderField("Apple", "Red"); + request.AddHTTPHeaderField("Kiwifruit", "Green"); + request.AddHTTPHeaderField("Content-Type", "application/octet-stream"); + request.AddHTTPHeaderField("Strawberry", "Red"); + + std::unique_ptr<ResourceRequest> preflight = + ThreadableLoader::CreateAccessControlPreflightRequestForTesting(request); + + EXPECT_EQ("apple,content-type,kiwifruit,orange,strawberry", + preflight->HttpHeaderField("Access-Control-Request-Headers")); +} + +TEST(ThreadableLoaderCreatePreflightRequestTest, ExcludeSimpleHeaders) { + ResourceRequest request; + request.AddHTTPHeaderField("Accept", "everything"); + request.AddHTTPHeaderField("Accept-Language", "everything"); + request.AddHTTPHeaderField("Content-Language", "everything"); + request.AddHTTPHeaderField("Save-Data", "on"); + + std::unique_ptr<ResourceRequest> preflight = + ThreadableLoader::CreateAccessControlPreflightRequestForTesting(request); + + // Do not emit empty-valued headers; an empty list of non-"CORS safelisted" + // request headers should cause "Access-Control-Request-Headers:" to be + // left out in the preflight request. + EXPECT_EQ(g_null_atom, + preflight->HttpHeaderField("Access-Control-Request-Headers")); +} + +TEST(ThreadableLoaderCreatePreflightRequestTest, + ExcludeSimpleContentTypeHeader) { + ResourceRequest request; + request.AddHTTPHeaderField("Content-Type", "text/plain"); + + std::unique_ptr<ResourceRequest> preflight = + ThreadableLoader::CreateAccessControlPreflightRequestForTesting(request); + + // Empty list also; see comment in test above. + EXPECT_EQ(g_null_atom, + preflight->HttpHeaderField("Access-Control-Request-Headers")); +} + +TEST(ThreadableLoaderCreatePreflightRequestTest, IncludeNonSimpleHeader) { + ResourceRequest request; + request.AddHTTPHeaderField("X-Custom-Header", "foobar"); + + std::unique_ptr<ResourceRequest> preflight = + ThreadableLoader::CreateAccessControlPreflightRequestForTesting(request); + + EXPECT_EQ("x-custom-header", + preflight->HttpHeaderField("Access-Control-Request-Headers")); +} + +TEST(ThreadableLoaderCreatePreflightRequestTest, + IncludeNonSimpleContentTypeHeader) { + ResourceRequest request; + request.AddHTTPHeaderField("Content-Type", "application/octet-stream"); + + std::unique_ptr<ResourceRequest> preflight = + ThreadableLoader::CreateAccessControlPreflightRequestForTesting(request); + + EXPECT_EQ("content-type", + preflight->HttpHeaderField("Access-Control-Request-Headers")); +} + } // namespace } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/worker_threadable_loader.cc b/third_party/blink/renderer/core/loader/worker_threadable_loader.cc deleted file mode 100644 index 7fe7bf5..0000000 --- a/third_party/blink/renderer/core/loader/worker_threadable_loader.cc +++ /dev/null
@@ -1,680 +0,0 @@ -/* - * Copyright (C) 2009, 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "third_party/blink/renderer/core/loader/worker_threadable_loader.h" - -#include <memory> - -#include "base/debug/alias.h" -#include "third_party/blink/public/platform/task_type.h" -#include "third_party/blink/renderer/core/loader/document_threadable_loader.h" -#include "third_party/blink/renderer/core/loader/threadable_loading_context.h" -#include "third_party/blink/renderer/core/timing/worker_global_scope_performance.h" -#include "third_party/blink/renderer/core/workers/worker_global_scope.h" -#include "third_party/blink/renderer/core/workers/worker_thread.h" -#include "third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.h" -#include "third_party/blink/renderer/platform/cross_thread_functional.h" -#include "third_party/blink/renderer/platform/heap/safe_point.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" -#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h" -#include "third_party/blink/renderer/platform/weborigin/kurl.h" -#include "third_party/blink/renderer/platform/weborigin/security_policy.h" -#include "third_party/blink/renderer/platform/wtf/functional.h" - -namespace blink { - -namespace { - -std::unique_ptr<Vector<char>> CreateVectorFromMemoryRegion( - const char* data, - unsigned data_length) { - std::unique_ptr<Vector<char>> buffer = - std::make_unique<Vector<char>>(data_length); - memcpy(buffer->data(), data, data_length); - return buffer; -} - -} // namespace - -struct WorkerThreadableLoader::TaskWithLocation final { - TaskWithLocation(const base::Location& location, CrossThreadClosure task) - : location_(location), task_(std::move(task)) {} - TaskWithLocation(TaskWithLocation&& task) - : TaskWithLocation(task.location_, std::move(task.task_)) {} - ~TaskWithLocation() = default; - - base::Location location_; - CrossThreadClosure task_; -}; - -// Observing functions and wait() need to be called on the worker thread. -// Setting functions and signal() need to be called on the parent thread. -// All observing functions must be called after wait() returns, and all -// setting functions must be called before signal() is called. -class WorkerThreadableLoader::WaitableEventWithTasks final - : public ThreadSafeRefCounted<WaitableEventWithTasks> { - public: - static scoped_refptr<WaitableEventWithTasks> Create( - scoped_refptr<base::SingleThreadTaskRunner> worker_loading_task_runner) { - return base::AdoptRef( - new WaitableEventWithTasks(worker_loading_task_runner)); - } - - void Signal() { -#if DCHECK_IS_ON() - DCHECK(!worker_loading_task_runner_->BelongsToCurrentThread()); -#endif - CHECK(!is_signal_called_); - is_signal_called_ = true; - event_.Signal(); - } - void Wait() { -#if DCHECK_IS_ON() - DCHECK(worker_loading_task_runner_->BelongsToCurrentThread()); -#endif - CHECK(!is_wait_done_); - event_.Wait(); - is_wait_done_ = true; - } - - // Observing functions - bool IsAborted() const { -#if DCHECK_IS_ON() - DCHECK(worker_loading_task_runner_->BelongsToCurrentThread()); -#endif - CHECK(is_wait_done_); - return is_aborted_; - } - Vector<TaskWithLocation> Take() { -#if DCHECK_IS_ON() - DCHECK(worker_loading_task_runner_->BelongsToCurrentThread()); -#endif - CHECK(is_wait_done_); - return std::move(tasks_); - } - - // Setting functions - void Append(TaskWithLocation task) { -#if DCHECK_IS_ON() - DCHECK(!worker_loading_task_runner_->BelongsToCurrentThread()); -#endif - CHECK(!is_signal_called_); - tasks_.push_back(std::move(task)); - } - void SetIsAborted() { -#if DCHECK_IS_ON() - DCHECK(!worker_loading_task_runner_->BelongsToCurrentThread()); -#endif - CHECK(!is_signal_called_); - is_aborted_ = true; - } - -#if DCHECK_IS_ON() - // A task runner from the WorkerGlobalScope that requested the fetch. - // Used for thread correctness DCHECKs. - scoped_refptr<base::SingleThreadTaskRunner> worker_loading_task_runner_; -#endif - - private: - explicit WaitableEventWithTasks( - scoped_refptr<base::SingleThreadTaskRunner> worker_loading_task_runner) { -#if DCHECK_IS_ON() - worker_loading_task_runner_ = worker_loading_task_runner; -#endif - } - - WaitableEvent event_; - Vector<TaskWithLocation> tasks_; - bool is_aborted_ = false; - bool is_signal_called_ = false; - bool is_wait_done_ = false; -}; - -WorkerThreadableLoader::TaskForwarder::TaskForwarder( - scoped_refptr<WaitableEventWithTasks> event_with_tasks) - : event_with_tasks_(std::move(event_with_tasks)) { -#if DCHECK_IS_ON() - DCHECK(!event_with_tasks_->worker_loading_task_runner_ - ->BelongsToCurrentThread()); -#endif -} - -void WorkerThreadableLoader::TaskForwarder::ForwardTask( - const base::Location& location, - CrossThreadClosure task) { -#if DCHECK_IS_ON() - DCHECK(!event_with_tasks_->worker_loading_task_runner_ - ->BelongsToCurrentThread()); -#endif - event_with_tasks_->Append(TaskWithLocation(location, std::move(task))); -} - -void WorkerThreadableLoader::TaskForwarder::ForwardTaskWithDoneSignal( - const base::Location& location, - CrossThreadClosure task) { -#if DCHECK_IS_ON() - DCHECK(!event_with_tasks_->worker_loading_task_runner_ - ->BelongsToCurrentThread()); -#endif - event_with_tasks_->Append(TaskWithLocation(location, std::move(task))); - event_with_tasks_->Signal(); -} - -void WorkerThreadableLoader::TaskForwarder::Abort() { -#if DCHECK_IS_ON() - DCHECK(!event_with_tasks_->worker_loading_task_runner_ - ->BelongsToCurrentThread()); -#endif - event_with_tasks_->SetIsAborted(); - event_with_tasks_->Signal(); -} - -WorkerThreadableLoader::WorkerThreadableLoader( - WorkerGlobalScope& worker_global_scope, - ThreadableLoaderClient* client, - const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resource_loader_options) - : worker_global_scope_(&worker_global_scope), - parent_execution_context_task_runners_( - worker_global_scope.GetThread() - ->GetParentExecutionContextTaskRunners()), - client_(client), - threadable_loader_options_(options), - resource_loader_options_(resource_loader_options) { - DCHECK(client); -} - -void WorkerThreadableLoader::LoadResourceSynchronously( - WorkerGlobalScope& worker_global_scope, - const ResourceRequest& request, - ThreadableLoaderClient& client, - const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resource_loader_options) { - (new WorkerThreadableLoader(worker_global_scope, &client, options, - resource_loader_options)) - ->Start(request); -} - -WorkerThreadableLoader::~WorkerThreadableLoader() { - DCHECK(!parent_thread_loader_holder_); - DCHECK(!client_); -} - -void WorkerThreadableLoader::Start(const ResourceRequest& original_request) { - DCHECK(worker_global_scope_->IsContextThread()); - ResourceRequest request(original_request); - if (!request.DidSetHTTPReferrer()) { - request.SetHTTPReferrer(SecurityPolicy::GenerateReferrer( - worker_global_scope_->GetReferrerPolicy(), request.Url(), - worker_global_scope_->OutgoingReferrer())); - } - - - WorkerThread* worker_thread = worker_global_scope_->GetThread(); - scoped_refptr<base::SingleThreadTaskRunner> worker_loading_task_runner = - worker_global_scope_->GetTaskRunner(TaskType::kInternalLoading); - scoped_refptr<WaitableEventWithTasks> event_with_tasks = - WaitableEventWithTasks::Create(worker_loading_task_runner); - PostCrossThreadTask( - *parent_execution_context_task_runners_->Get(TaskType::kInternalLoading), - FROM_HERE, - CrossThreadBind( - &ParentThreadLoaderHolder::CreateAndStart, - WrapCrossThreadPersistent(this), - WrapCrossThreadPersistent(worker_thread->GetLoadingContext()), - std::move(worker_loading_task_runner), - WrapCrossThreadPersistent( - worker_thread->GetWorkerThreadLifecycleContext()), - request, threadable_loader_options_, resource_loader_options_, - event_with_tasks)); - - event_with_tasks->Wait(); - - if (event_with_tasks->IsAborted()) { - // This thread is going to terminate. - Cancel(); - return; - } - - for (auto& task : event_with_tasks->Take()) { - // Store the program counter where the task is posted from, and alias - // it to ensure it is stored in the crash dump. - const void* program_counter = task.location_.program_counter(); - base::debug::Alias(&program_counter); - - std::move(task.task_).Run(); - } -} - -void WorkerThreadableLoader::OverrideTimeout( - unsigned long timeout_milliseconds) { - DCHECK(worker_global_scope_->IsContextThread()); - if (!parent_thread_loader_holder_) - return; - PostCrossThreadTask( - *parent_execution_context_task_runners_->Get(TaskType::kInternalLoading), - FROM_HERE, - CrossThreadBind(&ParentThreadLoaderHolder::OverrideTimeout, - parent_thread_loader_holder_, timeout_milliseconds)); -} - -void WorkerThreadableLoader::Cancel() { - DCHECK(worker_global_scope_->IsContextThread()); - if (parent_thread_loader_holder_) { - PostCrossThreadTask(*parent_execution_context_task_runners_->Get( - TaskType::kInternalLoading), - FROM_HERE, - CrossThreadBind(&ParentThreadLoaderHolder::Cancel, - parent_thread_loader_holder_)); - parent_thread_loader_holder_ = nullptr; - } - - if (!client_) - return; - - // If the client hasn't reached a termination state, then transition it - // by sending a cancellation error. - // Note: no more client callbacks will be done after this method -- the - // clearClient() call ensures that. - DidFail(ResourceError::CancelledError(KURL())); - DCHECK(!client_); -} - -void WorkerThreadableLoader::Detach() { - // NOTREACHED - // Currently only "synchronous" requests are using this class and we will - // deprecate it in the future. As this method cannot be called for such - // requests, we don't implement it. - CHECK(false); -} - -void WorkerThreadableLoader::DidStart( - ParentThreadLoaderHolder* parent_thread_loader_holder) { - DCHECK(worker_global_scope_->IsContextThread()); - DCHECK(!parent_thread_loader_holder_); - DCHECK(parent_thread_loader_holder); - if (!client_) { - // The thread is terminating. - PostCrossThreadTask(*parent_execution_context_task_runners_->Get( - TaskType::kInternalLoading), - FROM_HERE, - CrossThreadBind(&ParentThreadLoaderHolder::Cancel, - WrapCrossThreadPersistent( - parent_thread_loader_holder))); - return; - } - - parent_thread_loader_holder_ = parent_thread_loader_holder; -} - -void WorkerThreadableLoader::DidSendData( - unsigned long long bytes_sent, - unsigned long long total_bytes_to_be_sent) { - DCHECK(worker_global_scope_->IsContextThread()); - if (!client_) - return; - client_->DidSendData(bytes_sent, total_bytes_to_be_sent); -} - -void WorkerThreadableLoader::DidReceiveRedirectTo(const KURL& url) { - DCHECK(worker_global_scope_->IsContextThread()); - if (!client_) - return; - client_->DidReceiveRedirectTo(url); -} - -void WorkerThreadableLoader::DidReceiveResponse( - unsigned long identifier, - std::unique_ptr<CrossThreadResourceResponseData> response_data, - std::unique_ptr<WebDataConsumerHandle> handle) { - DCHECK(worker_global_scope_->IsContextThread()); - if (!client_) - return; - ResourceResponse response(response_data.get()); - client_->DidReceiveResponse(identifier, response, std::move(handle)); -} - -void WorkerThreadableLoader::DidReceiveData( - std::unique_ptr<Vector<char>> data) { - DCHECK(worker_global_scope_->IsContextThread()); - CHECK_LE(data->size(), std::numeric_limits<unsigned>::max()); - if (!client_) - return; - client_->DidReceiveData(data->data(), data->size()); -} - -void WorkerThreadableLoader::DidReceiveCachedMetadata( - std::unique_ptr<Vector<char>> data) { - DCHECK(worker_global_scope_->IsContextThread()); - if (!client_) - return; - client_->DidReceiveCachedMetadata(data->data(), data->size()); -} - -void WorkerThreadableLoader::DidFinishLoading(unsigned long identifier) { - DCHECK(worker_global_scope_->IsContextThread()); - if (!client_) - return; - auto* client = client_; - client_ = nullptr; - parent_thread_loader_holder_ = nullptr; - client->DidFinishLoading(identifier); -} - -void WorkerThreadableLoader::DidFail(const ResourceError& error) { - DCHECK(worker_global_scope_->IsContextThread()); - if (!client_) - return; - auto* client = client_; - client_ = nullptr; - parent_thread_loader_holder_ = nullptr; - client->DidFail(error); -} - -void WorkerThreadableLoader::DidFailRedirectCheck() { - DCHECK(worker_global_scope_->IsContextThread()); - if (!client_) - return; - auto* client = client_; - client_ = nullptr; - parent_thread_loader_holder_ = nullptr; - client->DidFailRedirectCheck(); -} - -void WorkerThreadableLoader::DidDownloadData(int data_length) { - DCHECK(worker_global_scope_->IsContextThread()); - if (!client_) - return; - client_->DidDownloadData(data_length); -} - -void WorkerThreadableLoader::DidDownloadToBlob( - scoped_refptr<BlobDataHandle> blob) { - DCHECK(worker_global_scope_->IsContextThread()); - if (!client_) - return; - client_->DidDownloadToBlob(std::move(blob)); -} - -void WorkerThreadableLoader::DidReceiveResourceTiming( - std::unique_ptr<CrossThreadResourceTimingInfoData> timing_data) { - DCHECK(worker_global_scope_->IsContextThread()); - if (!client_) - return; - scoped_refptr<ResourceTimingInfo> info( - ResourceTimingInfo::Adopt(std::move(timing_data))); - WorkerGlobalScopePerformance::performance(*worker_global_scope_) - ->GenerateAndAddResourceTiming(*info); - client_->DidReceiveResourceTiming(*info); -} - -void WorkerThreadableLoader::Trace(blink::Visitor* visitor) { - visitor->Trace(worker_global_scope_); - ThreadableLoader::Trace(visitor); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::CreateAndStart( - WorkerThreadableLoader* worker_loader, - ThreadableLoadingContext* loading_context, - scoped_refptr<base::SingleThreadTaskRunner> worker_loading_task_runner, - WorkerThreadLifecycleContext* worker_thread_lifecycle_context, - std::unique_ptr<CrossThreadResourceRequestData> request, - const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resource_loader_options, - scoped_refptr<WaitableEventWithTasks> event_with_tasks) { - DCHECK(loading_context->GetExecutionContext()->IsContextThread()); - DCHECK(event_with_tasks); - TaskForwarder* forwarder = new TaskForwarder(std::move(event_with_tasks)); - - ParentThreadLoaderHolder* parent_thread_loader_holder = - new ParentThreadLoaderHolder(forwarder, worker_thread_lifecycle_context); - if (parent_thread_loader_holder - ->WasContextDestroyedBeforeObserverCreation()) { - // The thread is already terminating. - forwarder->Abort(); - parent_thread_loader_holder->forwarder_ = nullptr; - return; - } - parent_thread_loader_holder->worker_loader_ = worker_loader; - forwarder->ForwardTask( - FROM_HERE, - CrossThreadBind(&WorkerThreadableLoader::DidStart, - WrapCrossThreadPersistent(worker_loader), - WrapCrossThreadPersistent(parent_thread_loader_holder))); - parent_thread_loader_holder->Start(*loading_context, std::move(request), - options, resource_loader_options); -} - -WorkerThreadableLoader::ParentThreadLoaderHolder::~ParentThreadLoaderHolder() { - DCHECK(!worker_loader_); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::OverrideTimeout( - unsigned long timeout_milliseconds) { - if (!parent_thread_loader_) - return; - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - parent_thread_loader_->OverrideTimeout(timeout_milliseconds); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::Cancel() { - worker_loader_ = nullptr; - if (!parent_thread_loader_) - return; - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - parent_thread_loader_->Cancel(); - parent_thread_loader_ = nullptr; -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidSendData( - unsigned long long bytes_sent, - unsigned long long total_bytes_to_be_sent) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Get(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTask( - FROM_HERE, - CrossThreadBind(&WorkerThreadableLoader::DidSendData, worker_loader, - bytes_sent, total_bytes_to_be_sent)); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidReceiveRedirectTo( - const KURL& url) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Get(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTask( - FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidReceiveRedirectTo, - worker_loader, url)); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidReceiveResponse( - unsigned long identifier, - const ResourceResponse& response, - std::unique_ptr<WebDataConsumerHandle> handle) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Get(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTask( - FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidReceiveResponse, - worker_loader, identifier, response, - WTF::Passed(std::move(handle)))); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidReceiveData( - const char* data, - unsigned data_length) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Get(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTask( - FROM_HERE, - CrossThreadBind( - &WorkerThreadableLoader::DidReceiveData, worker_loader, - WTF::Passed(CreateVectorFromMemoryRegion(data, data_length)))); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidDownloadData( - int data_length) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Get(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTask( - FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidDownloadData, - worker_loader, data_length)); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidDownloadToBlob( - scoped_refptr<BlobDataHandle> blob) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Get(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTask( - FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidDownloadToBlob, - worker_loader, std::move(blob))); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidReceiveCachedMetadata( - const char* data, - int data_length) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Get(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTask( - FROM_HERE, - CrossThreadBind( - &WorkerThreadableLoader::DidReceiveCachedMetadata, worker_loader, - WTF::Passed(CreateVectorFromMemoryRegion(data, data_length)))); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidFinishLoading( - unsigned long identifier) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Release(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTaskWithDoneSignal( - FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidFinishLoading, - worker_loader, identifier)); - forwarder_ = nullptr; -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidFail( - const ResourceError& error) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Release(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTaskWithDoneSignal( - FROM_HERE, - CrossThreadBind(&WorkerThreadableLoader::DidFail, worker_loader, error)); - forwarder_ = nullptr; -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidFailRedirectCheck() { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Release(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTaskWithDoneSignal( - FROM_HERE, CrossThreadBind(&WorkerThreadableLoader::DidFailRedirectCheck, - worker_loader)); - forwarder_ = nullptr; -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::DidReceiveResourceTiming( - const ResourceTimingInfo& info) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - CrossThreadPersistent<WorkerThreadableLoader> worker_loader = - worker_loader_.Get(); - if (!worker_loader || !forwarder_) - return; - forwarder_->ForwardTask( - FROM_HERE, - CrossThreadBind(&WorkerThreadableLoader::DidReceiveResourceTiming, - worker_loader, info)); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::ContextDestroyed( - WorkerThreadLifecycleContext*) { - DCHECK(parent_thread_loader_->GetExecutionContext()->IsContextThread()); - if (forwarder_) { - forwarder_->Abort(); - forwarder_ = nullptr; - } - Cancel(); -} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::Trace( - blink::Visitor* visitor) { - visitor->Trace(forwarder_); - visitor->Trace(parent_thread_loader_); - WorkerThreadLifecycleObserver::Trace(visitor); -} - -WorkerThreadableLoader::ParentThreadLoaderHolder::ParentThreadLoaderHolder( - TaskForwarder* forwarder, - WorkerThreadLifecycleContext* context) - : WorkerThreadLifecycleObserver(context), forwarder_(forwarder) {} - -void WorkerThreadableLoader::ParentThreadLoaderHolder::Start( - ThreadableLoadingContext& loading_context, - std::unique_ptr<CrossThreadResourceRequestData> request, - const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& original_resource_loader_options) { - DCHECK(loading_context.GetExecutionContext()->IsContextThread()); - ResourceLoaderOptions resource_loader_options = - original_resource_loader_options; - resource_loader_options.request_initiator_context = kWorkerContext; - parent_thread_loader_ = DocumentThreadableLoader::Create( - loading_context, this, options, resource_loader_options); - parent_thread_loader_->Start(ResourceRequest(request.get())); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/loader/worker_threadable_loader.h b/third_party/blink/renderer/core/loader/worker_threadable_loader.h deleted file mode 100644 index 25a6b5f..0000000 --- a/third_party/blink/renderer/core/loader/worker_threadable_loader.h +++ /dev/null
@@ -1,215 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WORKER_THREADABLE_LOADER_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WORKER_THREADABLE_LOADER_H_ - -#include <memory> -#include "base/location.h" -#include "base/memory/scoped_refptr.h" -#include "base/single_thread_task_runner.h" -#include "third_party/blink/renderer/core/loader/threadable_loader.h" -#include "third_party/blink/renderer/core/loader/threadable_loader_client.h" -#include "third_party/blink/renderer/core/workers/worker_thread.h" -#include "third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.h" -#include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/waitable_event.h" -#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" -#include "third_party/blink/renderer/platform/wtf/threading.h" -#include "third_party/blink/renderer/platform/wtf/vector.h" - -namespace blink { - -class DocumentThreadableLoader; -class ThreadableLoadingContext; -class ResourceError; -class ResourceRequest; -class ResourceResponse; -class WorkerGlobalScope; -class WorkerThreadLifecycleContext; -struct CrossThreadResourceRequestData; -struct CrossThreadResourceTimingInfoData; - -// A WorkerThreadableLoader is a ThreadableLoader implementation intended to -// be used in a WebWorker thread. Because redirect handling doesn't perform CORS -// checks for sync requests, a WorkerThreadableLoader holds a ThreadableLoader -// in the parent thread and delegates tasks asynchronously to the loader. -// The parent thread may be the main thread, or in the case of nested workers, -// a different worker thread. -// -// CTP: CrossThreadPersistent -// CTWP: CrossThreadWeakPersistent -// -// ---------------------------------------------------------------- -// +------------------------+ -// raw ptr | ThreadableLoaderClient | -// +--------> | worker thread | -// | +------------------------+ -// | -// +----+------------------+ CTP +------------------------+ -// + WorkerThreadableLoader|<--------+ ParentThreadLoaderHolder | -// | worker thread +-------->| parent thread | -// +-----------------------+ CTWP +----------------------+-+ -// | -// +------------------+ | Member -// | ThreadableLoader | <---+ -// | parent thread | -// +------------------+ -// -class WorkerThreadableLoader final : public ThreadableLoader { - public: - static void LoadResourceSynchronously(WorkerGlobalScope&, - const ResourceRequest&, - ThreadableLoaderClient&, - const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); - ~WorkerThreadableLoader() override; - - // ThreadableLoader functions - void Start(const ResourceRequest&) override; - void OverrideTimeout(unsigned long timeout) override; - void Cancel() override; - void Detach() override; - - void Trace(blink::Visitor*) override; - - private: - struct TaskWithLocation; - class WaitableEventWithTasks; - // A TaskForwarder forwards a task to the worker thread. - class TaskForwarder final : public GarbageCollectedFinalized<TaskForwarder> { - public: - explicit TaskForwarder( - scoped_refptr<WaitableEventWithTasks> event_with_tasks); - ~TaskForwarder() = default; - void ForwardTask(const base::Location&, CrossThreadClosure); - void ForwardTaskWithDoneSignal(const base::Location&, CrossThreadClosure); - void Abort(); - void Trace(blink::Visitor* visitor) {} - - private: - scoped_refptr<WaitableEventWithTasks> event_with_tasks_; - }; - - // An instance of this class lives in the parent thread. It is a - // ThreadableLoaderClient for a DocumentThreadableLoader and forward - // notifications to the associated WorkerThreadableLoader living in the - // worker thread. - class ParentThreadLoaderHolder final - : public GarbageCollectedFinalized<ParentThreadLoaderHolder>, - public ThreadableLoaderClient, - public WorkerThreadLifecycleObserver { - USING_GARBAGE_COLLECTED_MIXIN(ParentThreadLoaderHolder); - USING_PRE_FINALIZER(ParentThreadLoaderHolder, Cancel); - - public: - static void CreateAndStart(WorkerThreadableLoader*, - ThreadableLoadingContext*, - scoped_refptr<base::SingleThreadTaskRunner>, - WorkerThreadLifecycleContext*, - std::unique_ptr<CrossThreadResourceRequestData>, - const ThreadableLoaderOptions&, - const ResourceLoaderOptions&, - scoped_refptr<WaitableEventWithTasks>); - ~ParentThreadLoaderHolder() override; - - void OverrideTimeout(unsigned long timeout_millisecond); - void Cancel(); - - void DidSendData(unsigned long long bytes_sent, - unsigned long long total_bytes_to_be_sent) override; - void DidReceiveRedirectTo(const KURL&) override; - void DidReceiveResponse(unsigned long identifier, - const ResourceResponse&, - std::unique_ptr<WebDataConsumerHandle>) override; - void DidReceiveData(const char*, unsigned data_length) override; - void DidDownloadData(int data_length) override; - void DidDownloadToBlob(scoped_refptr<BlobDataHandle>) override; - void DidReceiveCachedMetadata(const char*, int data_length) override; - void DidFinishLoading(unsigned long identifier) override; - void DidFail(const ResourceError&) override; - void DidFailRedirectCheck() override; - void DidReceiveResourceTiming(const ResourceTimingInfo&) override; - - void ContextDestroyed(WorkerThreadLifecycleContext*) override; - - void Trace(blink::Visitor*) override; - - private: - ParentThreadLoaderHolder(TaskForwarder*, WorkerThreadLifecycleContext*); - void Start(ThreadableLoadingContext&, - std::unique_ptr<CrossThreadResourceRequestData>, - const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); - - Member<TaskForwarder> forwarder_; - Member<DocumentThreadableLoader> parent_thread_loader_; - - // |*m_workerLoader| lives in the worker thread. - CrossThreadWeakPersistent<WorkerThreadableLoader> worker_loader_; - }; - - WorkerThreadableLoader(WorkerGlobalScope&, - ThreadableLoaderClient*, - const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); - void DidStart(ParentThreadLoaderHolder*); - - void DidSendData(unsigned long long bytes_sent, - unsigned long long total_bytes_to_be_sent); - void DidReceiveRedirectTo(const KURL&); - void DidReceiveResponse(unsigned long identifier, - std::unique_ptr<CrossThreadResourceResponseData>, - std::unique_ptr<WebDataConsumerHandle>); - void DidReceiveData(std::unique_ptr<Vector<char>> data); - void DidReceiveCachedMetadata(std::unique_ptr<Vector<char>> data); - void DidFinishLoading(unsigned long identifier); - void DidFail(const ResourceError&); - void DidFailRedirectCheck(); - void DidDownloadData(int data_length); - void DidDownloadToBlob(scoped_refptr<BlobDataHandle>); - void DidReceiveResourceTiming( - std::unique_ptr<CrossThreadResourceTimingInfoData>); - - Member<WorkerGlobalScope> worker_global_scope_; - CrossThreadPersistent<ParentExecutionContextTaskRunners> - parent_execution_context_task_runners_; - ThreadableLoaderClient* client_; - - ThreadableLoaderOptions threadable_loader_options_; - ResourceLoaderOptions resource_loader_options_; - - // |parent_thread_loader_holder_| lives in the parent thread. - CrossThreadPersistent<ParentThreadLoaderHolder> parent_thread_loader_holder_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_WORKER_THREADABLE_LOADER_H_
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.cc b/third_party/blink/renderer/core/paint/background_image_geometry.cc index 1c4c1db2..86da0e1 100644 --- a/third_party/blink/renderer/core/paint/background_image_geometry.cc +++ b/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -795,7 +795,6 @@ // positioning_area_size in that dimension, so that rounding of floating // point approximation to LayoutUnit do not shrink the image to smaller // than the positioning_area_size. - LayoutSize tile_size; if (type == EFillSizeType::kContain) { // Snap the dependent dimension to avoid bleeding/blending artifacts // at the edge of the image when we paint it.
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc index c900e89..008beae4 100644 --- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc +++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -102,7 +102,6 @@ if (!layout_object.IsBox()) return IntRect(); - LayoutRect rect; const LayoutBox& box = ToLayoutBox(layout_object); return PixelSnappedIntRect(box.BackgroundRect(kBackgroundClipRect)); } @@ -1342,6 +1341,7 @@ IntSize scroll_offset = layout_box.ScrolledContentOffset(); IntPoint scroll_origin = compositing_container->GetScrollableArea()->ScrollOrigin(); + scroll_origin.Move(-layout_box.OriginAdjustmentForScrollbars()); scroll_origin.Move(-layout_box.BorderLeft().ToInt(), -layout_box.BorderTop().ToInt()); graphics_layer_parent_location = -(scroll_origin + scroll_offset);
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc index 17085010..5dd25cad 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -275,9 +275,6 @@ if (!ShouldPaintTextFragment(text_fragment, style)) return; - NGPhysicalSize size_; - NGPhysicalOffset offset_; - // We round the y-axis to ensure consistent line heights. LayoutPoint adjusted_paint_offset = LayoutPoint(paint_offset.X(), LayoutUnit(paint_offset.Y().Round()));
diff --git a/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc b/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc index 3aaa55a..ca9f272 100644 --- a/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc +++ b/third_party/blink/renderer/core/paint/nine_piece_image_grid_test.cc
@@ -93,7 +93,6 @@ IntSize image_size(100, 100); IntRect border_image_area(0, 0, 100, 100); - IntRectOutsets border_widths(10, 10, 10, 10); const struct { IntRectOutsets border_widths;
diff --git a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc index 555574a..b6e5237 100644 --- a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc +++ b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
@@ -131,7 +131,7 @@ v8::Local<v8::Value> exported_value = module_namespace->Get(context, V8String(isolate, export_name_)) .ToLocalChecked(); - captured_value_ = ToCoreString(exported_value->ToString()); + captured_value_ = ToCoreString(exported_value->ToString(isolate)); return ScriptValue(); } @@ -165,11 +165,11 @@ v8::Local<v8::Value> name = error_object->Get(context, V8String(isolate, "name")).ToLocalChecked(); - name_ = ToCoreString(name->ToString()); + name_ = ToCoreString(name->ToString(isolate)); v8::Local<v8::Value> message = error_object->Get(context, V8String(isolate, "message")) .ToLocalChecked(); - message_ = ToCoreString(message->ToString()); + message_ = ToCoreString(message->ToString(isolate)); return ScriptValue(); }
diff --git a/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc b/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc index 33154781..17abd69 100644 --- a/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc +++ b/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc
@@ -62,7 +62,7 @@ is_valid_ = false; return; } - value_ = ToCoreString(value->ToString()); + value_ = ToCoreString(value->ToString(v.GetScriptState()->GetIsolate())); } bool IsSet() const { return is_set_; }
diff --git a/third_party/blink/renderer/core/testing/dictionary_test.cc b/third_party/blink/renderer/core/testing/dictionary_test.cc index 0c32750..9eafb7c 100644 --- a/third_party/blink/renderer/core/testing/dictionary_test.cc +++ b/third_party/blink/renderer/core/testing/dictionary_test.cc
@@ -221,7 +221,7 @@ v8::Local<v8::Value> value; if (iterator.GetValue().ToLocal(&value)) - result.Append(ToCoreString(value->ToString())); + result.Append(ToCoreString(value->ToString(script_state->GetIsolate()))); } return result.ToString();
diff --git a/third_party/blink/renderer/core/testing/dummy_page_holder.h b/third_party/blink/renderer/core/testing/dummy_page_holder.h index c9df0aa..edb29e145 100644 --- a/third_party/blink/renderer/core/testing/dummy_page_holder.h +++ b/third_party/blink/renderer/core/testing/dummy_page_holder.h
@@ -87,7 +87,7 @@ Persistent<Page> page_; // The LocalFrame is accessed from worker threads by unit tests - // (WorkerThreadableLoaderTest), hence we need to allow cross-thread + // (ThreadableLoaderTest), hence we need to allow cross-thread // usage of |m_frame|. // // TODO: rework the tests to not require cross-thread access.
diff --git a/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc b/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc index 6e803af..29686dd 100644 --- a/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc +++ b/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
@@ -52,8 +52,8 @@ WorkerClassicScriptLoader::~WorkerClassicScriptLoader() { // If |m_threadableLoader| is still working, we have to cancel it here. - // Otherwise didFail() of the deleted |this| will be called from - // DocumentThreadableLoader::notifyFinished() when the frame will be + // Otherwise DidFail() of the deleted |this| will be called from + // ThreadableLoader::NotifyFinished() when the frame will be // destroyed. if (need_to_cancel_) Cancel();
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.cc b/third_party/blink/renderer/core/workers/worker_global_scope.cc index e5fe2f5..615a282 100644 --- a/third_party/blink/renderer/core/workers/worker_global_scope.cc +++ b/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -44,7 +44,7 @@ #include "third_party/blink/renderer/core/inspector/console_message_storage.h" #include "third_party/blink/renderer/core/inspector/worker_inspector_controller.h" #include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h" -#include "third_party/blink/renderer/core/loader/worker_threadable_loader.h" +#include "third_party/blink/renderer/core/loader/threadable_loader.h" #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h" #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_event.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_event.idl index f4faa5c..42273030d 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_event.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_event.idl
@@ -10,5 +10,5 @@ RuntimeEnabled=BackgroundFetch ] interface BackgroundFetchUpdateEvent : BackgroundFetchSettledEvent { - [CallWith=ScriptState] Promise<void> updateUI(BackgroundFetchUpdateUIOptions title); + [CallWith=ScriptState] Promise<void> updateUI(BackgroundFetchUpdateUIOptions options); }; \ No newline at end of file
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc index 208ff8c..eada762 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -123,7 +123,7 @@ CanvasElement().DidDraw(); CanvasElement().FinalizeFrame(); // Grabbing an image forces a flush - CanvasElement().CopiedImage(kBackBuffer, kPreferAcceleration); + CanvasElement().Snapshot(kBackBuffer, kPreferAcceleration); } enum LatencyMode { kNormalLatency, kLowLatency };
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index d22b722..ab53b3f 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1543,8 +1543,6 @@ if (!marked_canvas_dirty_ && !must_clear_now) return false; - if (canvas()) - canvas()->ClearCopiedImage(); marked_canvas_dirty_ = false; if (!Host()->GetOrCreateCanvasResourceProvider(kPreferAcceleration)) @@ -5240,7 +5238,7 @@ if (!canvas->IsAccelerated() || !CanUseTexImageByGPU(format, type)) { TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset, zoffset, format, type, - canvas->CopiedImage(kBackBuffer, kPreferAcceleration).get(), + canvas->Snapshot(kBackBuffer, kPreferAcceleration).get(), WebGLImageConversion::kHtmlDomCanvas, unpack_flip_y_, unpack_premultiply_alpha_, source_sub_rectangle, 1, 0); return; @@ -5271,7 +5269,7 @@ // textures, and elements of 2D texture arrays. TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset, zoffset, format, type, - canvas->CopiedImage(kBackBuffer, kPreferAcceleration).get(), + canvas->Snapshot(kBackBuffer, kPreferAcceleration).get(), WebGLImageConversion::kHtmlDomCanvas, unpack_flip_y_, unpack_premultiply_alpha_, source_sub_rectangle, depth, unpack_image_height);
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 41efb00..916a81f 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1164,8 +1164,6 @@ "lifecycle_observer.h", "link_hash.cc", "link_hash.h", - "long_task_detector.cc", - "long_task_detector.h", "mac/block_exceptions.h", "mac/block_exceptions.mm", "mac/color_mac.h", @@ -1823,7 +1821,6 @@ "json/json_values_test.cc", "layout_unit_test.cc", "lifecycle_context_test.cc", - "long_task_detector_test.cc", "mac/graphics_context_canvas_test.mm", "mac/version_util_mac_test.mm", "mhtml/mhtml_parser_test.cc",
diff --git a/third_party/blink/renderer/platform/animation/DEPS b/third_party/blink/renderer/platform/animation/DEPS index 26f742b27..d15d7b3 100644 --- a/third_party/blink/renderer/platform/animation/DEPS +++ b/third_party/blink/renderer/platform/animation/DEPS
@@ -10,7 +10,6 @@ "+third_party/blink/renderer/platform/geometry", "+third_party/blink/renderer/platform/graphics", "+third_party/blink/renderer/platform/heap", - "+third_party/blink/renderer/platform/instrumentation", "+third_party/blink/renderer/platform/layout_unit.h", "+third_party/blink/renderer/platform/platform_export.h", "+third_party/blink/renderer/platform/runtime_enabled_features.h",
diff --git a/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc b/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc index 8e727fd6..1b339b18 100644 --- a/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc +++ b/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.cc
@@ -72,7 +72,7 @@ return FloatPoint(target.x(), target.y()); } -void CompositorScrollOffsetAnimationCurve::UpdateTarget(double time, +void CompositorScrollOffsetAnimationCurve::UpdateTarget(TimeDelta time, FloatPoint new_target) { curve_->UpdateTarget(time, gfx::ScrollOffset(new_target.X(), new_target.Y())); }
diff --git a/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h b/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h index a4c0291..7b2dec4d 100644 --- a/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h +++ b/third_party/blink/renderer/platform/animation/compositor_scroll_offset_animation_curve.h
@@ -12,6 +12,7 @@ #include "third_party/blink/renderer/platform/geometry/float_point.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/noncopyable.h" +#include "third_party/blink/renderer/platform/wtf/time.h" namespace cc { class ScrollOffsetAnimationCurve; @@ -49,7 +50,7 @@ double Duration() const; FloatPoint TargetValue() const; void ApplyAdjustment(IntSize); - void UpdateTarget(double time, FloatPoint new_target); + void UpdateTarget(TimeDelta time, FloatPoint new_target); // CompositorAnimationCurve implementation. std::unique_ptr<cc::AnimationCurve> CloneToAnimationCurve() const override;
diff --git a/third_party/blink/renderer/platform/bindings/DEPS b/third_party/blink/renderer/platform/bindings/DEPS index f59246c..87cfbf26 100644 --- a/third_party/blink/renderer/platform/bindings/DEPS +++ b/third_party/blink/renderer/platform/bindings/DEPS
@@ -13,7 +13,6 @@ "+third_party/blink/renderer/platform/platform_export.h", "+third_party/blink/renderer/platform/runtime_enabled_features.h", "+third_party/blink/renderer/platform/scheduler", - "+third_party/blink/renderer/platform/supplementable.h", "+third_party/blink/renderer/platform/testing", "+third_party/blink/renderer/platform/weborigin", "+third_party/blink/renderer/platform/wtf",
diff --git a/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.cc b/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.cc index 2ab286e..2f343483 100644 --- a/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.cc +++ b/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.cc
@@ -19,7 +19,6 @@ #include "third_party/blink/renderer/platform/heap/heap_page.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h" -#include "third_party/blink/renderer/platform/supplementable.h" #include "third_party/blink/renderer/platform/wtf/time.h" namespace blink {
diff --git a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.cc b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.cc index af5b491..af72ecc 100644 --- a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.cc +++ b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.cc
@@ -12,9 +12,10 @@ DCHECK(isolate); v8::HandleScope handle_scope(isolate); v8::Local<v8::String> target_string = - (string_.IsEmpty()) ? V8String(isolate, string) - : v8::String::Concat(string_.NewLocal(isolate), - V8String(isolate, string)); + (string_.IsEmpty()) + ? V8String(isolate, string) + : v8::String::Concat(isolate, string_.NewLocal(isolate), + V8String(isolate, string)); string_.Set(isolate, target_string); }
diff --git a/third_party/blink/renderer/platform/blob/DEPS b/third_party/blink/renderer/platform/blob/DEPS index 24f7593..299df734 100644 --- a/third_party/blink/renderer/platform/blob/DEPS +++ b/third_party/blink/renderer/platform/blob/DEPS
@@ -7,11 +7,9 @@ # Dependencies. "+third_party/blink/renderer/platform/cross_thread_functional.h", - "+third_party/blink/renderer/platform/file_metadata.h", "+third_party/blink/renderer/platform/histogram.h", "+third_party/blink/renderer/platform/instrumentation", "+third_party/blink/renderer/platform/platform_export.h", - "+third_party/blink/renderer/platform/runtime_enabled_features.h", "+third_party/blink/renderer/platform/testing", "+third_party/blink/renderer/platform/text/line_ending.h", "+third_party/blink/renderer/platform/uuid.h",
diff --git a/third_party/blink/renderer/platform/blob/blob_data.cc b/third_party/blink/renderer/platform/blob/blob_data.cc index 543574f..678cee04 100644 --- a/third_party/blink/renderer/platform/blob/blob_data.cc +++ b/third_party/blink/renderer/platform/blob/blob_data.cc
@@ -46,7 +46,6 @@ #include "third_party/blink/renderer/platform/cross_thread_functional.h" #include "third_party/blink/renderer/platform/histogram.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" -#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/text/line_ending.h" #include "third_party/blink/renderer/platform/uuid.h" #include "third_party/blink/renderer/platform/web_task_runner.h"
diff --git a/third_party/blink/renderer/platform/blob/blob_data.h b/third_party/blink/renderer/platform/blob/blob_data.h index e51d4c05..1afc9f231 100644 --- a/third_party/blink/renderer/platform/blob/blob_data.h +++ b/third_party/blink/renderer/platform/blob/blob_data.h
@@ -36,7 +36,6 @@ #include "base/thread_annotations.h" #include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" #include "third_party/blink/public/mojom/blob/data_element.mojom-blink.h" -#include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/platform/exported/DEPS b/third_party/blink/renderer/platform/exported/DEPS index 7e486bb..53f699c 100644 --- a/third_party/blink/renderer/platform/exported/DEPS +++ b/third_party/blink/renderer/platform/exported/DEPS
@@ -2,6 +2,4 @@ include_rules = [ "+net/cookies/canonical_cookie.h", "+net/cookies/cookie_constants.h", - "+net/cookies/canonical_cookie.h", - "+net/cookies/cookie_constants.h", ]
diff --git a/third_party/blink/renderer/platform/fonts/DEPS b/third_party/blink/renderer/platform/fonts/DEPS index 98ddf83..d6d83677 100644 --- a/third_party/blink/renderer/platform/fonts/DEPS +++ b/third_party/blink/renderer/platform/fonts/DEPS
@@ -9,7 +9,6 @@ "+third_party/blink/renderer/platform/font_family_names.h", "+third_party/blink/renderer/platform/geometry", "+third_party/blink/renderer/platform/graphics", - "+third_party/blink/renderer/platform/heap/handle.h", "+third_party/blink/renderer/platform/heap", "+third_party/blink/renderer/platform/histogram.h", "+third_party/blink/renderer/platform/instrumentation", @@ -23,6 +22,5 @@ "+third_party/blink/renderer/platform/shared_buffer.h", "+third_party/blink/renderer/platform/testing", "+third_party/blink/renderer/platform/text", - "+third_party/blink/renderer/platform/transforms/affine_transform.h", "+third_party/blink/renderer/platform/wtf", ]
diff --git a/third_party/blink/renderer/platform/fonts/font.cc b/third_party/blink/renderer/platform/fonts/font.cc index 140c9e34..a67e4393 100644 --- a/third_party/blink/renderer/platform/fonts/font.cc +++ b/third_party/blink/renderer/platform/fonts/font.cc
@@ -37,13 +37,11 @@ #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_text_blob.h" -#include "third_party/blink/renderer/platform/layout_test_support.h" #include "third_party/blink/renderer/platform/layout_unit.h" #include "third_party/blink/renderer/platform/text/bidi_resolver.h" #include "third_party/blink/renderer/platform/text/character.h" #include "third_party/blink/renderer/platform/text/text_run.h" #include "third_party/blink/renderer/platform/text/text_run_iterator.h" -#include "third_party/blink/renderer/platform/transforms/affine_transform.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/text/character_names.h" #include "third_party/blink/renderer/platform/wtf/text/unicode.h"
diff --git a/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc b/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc index b02c8ac..b37971a9 100644 --- a/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc +++ b/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc
@@ -40,7 +40,6 @@ #include "third_party/blink/renderer/platform/fonts/web_font_decoder.h" #include "third_party/blink/renderer/platform/fonts/web_font_typeface_factory.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_typeface.h" -#include "third_party/blink/renderer/platform/layout_test_support.h" #include "third_party/blink/renderer/platform/shared_buffer.h" #include "third_party/skia/include/core/SkStream.h" #include "third_party/skia/include/core/SkTypeface.h"
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm b/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm index 63b185c..0c0a983 100644 --- a/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm +++ b/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm
@@ -33,7 +33,6 @@ #import <Foundation/Foundation.h> #import <math.h> #include "third_party/blink/renderer/platform/fonts/font_cache.h" -#include "third_party/blink/renderer/platform/layout_test_support.h" #include "third_party/blink/renderer/platform/mac/version_util_mac.h" #import "third_party/blink/renderer/platform/wtf/hash_set.h" #import "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
diff --git a/third_party/blink/renderer/platform/geometry/double_point.h b/third_party/blink/renderer/platform/geometry/double_point.h index 9b25148..ece8413 100644 --- a/third_party/blink/renderer/platform/geometry/double_point.h +++ b/third_party/blink/renderer/platform/geometry/double_point.h
@@ -20,27 +20,27 @@ DISALLOW_NEW(); public: - DoublePoint() : x_(0), y_(0) {} - DoublePoint(double x, double y) : x_(x), y_(y) {} - DoublePoint(const IntPoint& p) : x_(p.X()), y_(p.Y()) {} - DoublePoint(const FloatPoint& p) : x_(p.X()), y_(p.Y()) {} + constexpr DoublePoint() : x_(0), y_(0) {} + constexpr DoublePoint(double x, double y) : x_(x), y_(y) {} + constexpr DoublePoint(const IntPoint& p) : x_(p.X()), y_(p.Y()) {} + constexpr DoublePoint(const FloatPoint& p) : x_(p.X()), y_(p.Y()) {} explicit DoublePoint(const LayoutPoint&); - explicit DoublePoint(const IntSize& size) + constexpr explicit DoublePoint(const IntSize& size) : x_(size.Width()), y_(size.Height()) {} explicit DoublePoint(const FloatSize&); - explicit DoublePoint(const DoubleSize& size) + constexpr explicit DoublePoint(const DoubleSize& size) : x_(size.Width()), y_(size.Height()) {} - static DoublePoint Zero() { return DoublePoint(); } + static constexpr DoublePoint Zero() { return DoublePoint(); } DoublePoint ExpandedTo(const DoublePoint&) const; DoublePoint ShrunkTo(const DoublePoint&) const; - double X() const { return x_; } - double Y() const { return y_; } + constexpr double X() const { return x_; } + constexpr double Y() const { return y_; } void SetX(double x) { x_ = x; } void SetY(double y) { y_ = y; } @@ -74,12 +74,12 @@ double x_, y_; }; -inline bool operator==(const DoublePoint& a, const DoublePoint& b) { +constexpr bool operator==(const DoublePoint& a, const DoublePoint& b) { return a.X() == b.X() && a.Y() == b.Y(); } -inline bool operator!=(const DoublePoint& a, const DoublePoint& b) { - return a.X() != b.X() || a.Y() != b.Y(); +constexpr bool operator!=(const DoublePoint& a, const DoublePoint& b) { + return !(a == b); } inline DoublePoint& operator+=(DoublePoint& a, const DoubleSize& b) { @@ -94,19 +94,19 @@ return a; } -inline DoublePoint operator+(const DoublePoint& a, const DoubleSize& b) { +constexpr DoublePoint operator+(const DoublePoint& a, const DoubleSize& b) { return DoublePoint(a.X() + b.Width(), a.Y() + b.Height()); } -inline DoubleSize operator-(const DoublePoint& a, const DoublePoint& b) { +constexpr DoubleSize operator-(const DoublePoint& a, const DoublePoint& b) { return DoubleSize(a.X() - b.X(), a.Y() - b.Y()); } -inline DoublePoint operator-(const DoublePoint& a) { +constexpr DoublePoint operator-(const DoublePoint& a) { return DoublePoint(-a.X(), -a.Y()); } -inline DoublePoint operator-(const DoublePoint& a, const DoubleSize& b) { +constexpr DoublePoint operator-(const DoublePoint& a, const DoubleSize& b) { return DoublePoint(a.X() - b.Width(), a.Y() - b.Height()); } @@ -122,11 +122,11 @@ return IntPoint(clampTo<int>(floor(p.X())), clampTo<int>(floor(p.Y()))); } -inline FloatPoint ToFloatPoint(const DoublePoint& a) { +constexpr FloatPoint ToFloatPoint(const DoublePoint& a) { return FloatPoint(a.X(), a.Y()); } -inline DoubleSize ToDoubleSize(const DoublePoint& a) { +constexpr DoubleSize ToDoubleSize(const DoublePoint& a) { return DoubleSize(a.X(), a.Y()); }
diff --git a/third_party/blink/renderer/platform/geometry/double_rect.h b/third_party/blink/renderer/platform/geometry/double_rect.h index c8f8b92e..d0560dae 100644 --- a/third_party/blink/renderer/platform/geometry/double_rect.h +++ b/third_party/blink/renderer/platform/geometry/double_rect.h
@@ -20,35 +20,35 @@ STACK_ALLOCATED(); public: - DoubleRect() = default; - DoubleRect(const DoublePoint& location, const DoubleSize& size) + constexpr DoubleRect() = default; + constexpr DoubleRect(const DoublePoint& location, const DoubleSize& size) : location_(location), size_(size) {} - DoubleRect(double x, double y, double width, double height) + constexpr DoubleRect(double x, double y, double width, double height) : location_(DoublePoint(x, y)), size_(DoubleSize(width, height)) {} DoubleRect(const IntRect&); DoubleRect(const FloatRect&); DoubleRect(const LayoutRect&); - DoublePoint Location() const { return location_; } - DoubleSize Size() const { return size_; } + constexpr DoublePoint Location() const { return location_; } + constexpr DoubleSize Size() const { return size_; } void SetLocation(const DoublePoint& location) { location_ = location; } void SetSize(const DoubleSize& size) { size_ = size; } - double X() const { return location_.X(); } - double Y() const { return location_.Y(); } - double MaxX() const { return X() + Width(); } - double MaxY() const { return Y() + Height(); } - double Width() const { return size_.Width(); } - double Height() const { return size_.Height(); } + constexpr double X() const { return location_.X(); } + constexpr double Y() const { return location_.Y(); } + constexpr double MaxX() const { return X() + Width(); } + constexpr double MaxY() const { return Y() + Height(); } + constexpr double Width() const { return size_.Width(); } + constexpr double Height() const { return size_.Height(); } void SetX(double x) { location_.SetX(x); } void SetY(double y) { location_.SetY(y); } void SetWidth(double width) { size_.SetWidth(width); } void SetHeight(double height) { size_.SetHeight(height); } - bool IsEmpty() const { return size_.IsEmpty(); } - bool IsZero() const { return size_.IsZero(); } + constexpr bool IsEmpty() const { return size_.IsEmpty(); } + constexpr bool IsZero() const { return size_.IsZero(); } void Move(const DoubleSize& delta) { location_ += delta; } void Move(double dx, double dy) { location_.Move(dx, dy); } @@ -56,14 +56,16 @@ location_.Move(delta.X(), delta.Y()); } - DoublePoint MinXMinYCorner() const { return location_; } // typically topLeft - DoublePoint MaxXMinYCorner() const { + constexpr DoublePoint MinXMinYCorner() const { + return location_; + } // typically topLeft + constexpr DoublePoint MaxXMinYCorner() const { return DoublePoint(location_.X() + size_.Width(), location_.Y()); } // typically topRight - DoublePoint MinXMaxYCorner() const { + constexpr DoublePoint MinXMaxYCorner() const { return DoublePoint(location_.X(), location_.Y() + size_.Height()); } // typically bottomLeft - DoublePoint MaxXMaxYCorner() const { + constexpr DoublePoint MaxXMaxYCorner() const { return DoublePoint(location_.X() + size_.Width(), location_.Y() + size_.Height()); } // typically bottomRight
diff --git a/third_party/blink/renderer/platform/geometry/double_size.h b/third_party/blink/renderer/platform/geometry/double_size.h index 917c81c4c..a5ce8eb 100644 --- a/third_party/blink/renderer/platform/geometry/double_size.h +++ b/third_party/blink/renderer/platform/geometry/double_size.h
@@ -19,20 +19,22 @@ DISALLOW_NEW(); public: - DoubleSize() : width_(0), height_(0) {} - DoubleSize(double width, double height) : width_(width), height_(height) {} - explicit DoubleSize(const IntSize& p) + constexpr DoubleSize() : width_(0), height_(0) {} + constexpr DoubleSize(double width, double height) + : width_(width), height_(height) {} + constexpr explicit DoubleSize(const IntSize& p) : width_(p.Width()), height_(p.Height()) {} - DoubleSize(const FloatSize& s) : width_(s.Width()), height_(s.Height()) {} + constexpr DoubleSize(const FloatSize& s) + : width_(s.Width()), height_(s.Height()) {} explicit DoubleSize(const LayoutSize&); - double Width() const { return width_; } - double Height() const { return height_; } + constexpr double Width() const { return width_; } + constexpr double Height() const { return height_; } void SetWidth(double width) { width_ = width; } void SetHeight(double height) { height_ = height; } - bool IsEmpty() const { return width_ <= 0 || height_ <= 0; } + constexpr bool IsEmpty() const { return width_ <= 0 || height_ <= 0; } bool IsZero() const; @@ -66,19 +68,19 @@ return a; } -inline DoubleSize operator+(const DoubleSize& a, const DoubleSize& b) { +constexpr DoubleSize operator+(const DoubleSize& a, const DoubleSize& b) { return DoubleSize(a.Width() + b.Width(), a.Height() + b.Height()); } -inline DoubleSize operator-(const DoubleSize& a, const DoubleSize& b) { +constexpr DoubleSize operator-(const DoubleSize& a, const DoubleSize& b) { return DoubleSize(a.Width() - b.Width(), a.Height() - b.Height()); } -inline bool operator==(const DoubleSize& a, const DoubleSize& b) { +constexpr bool operator==(const DoubleSize& a, const DoubleSize& b) { return a.Width() == b.Width() && a.Height() == b.Height(); } -inline bool operator!=(const DoubleSize& a, const DoubleSize& b) { +constexpr bool operator!=(const DoubleSize& a, const DoubleSize& b) { return a.Width() != b.Width() || a.Height() != b.Height(); } @@ -96,7 +98,7 @@ return IntSize(clampTo<int>(ceil(p.Width())), clampTo<int>(ceil(p.Height()))); } -inline FloatSize ToFloatSize(const DoubleSize& p) { +constexpr FloatSize ToFloatSize(const DoubleSize& p) { return FloatSize(p.Width(), p.Height()); }
diff --git a/third_party/blink/renderer/platform/geometry/float_box.h b/third_party/blink/renderer/platform/geometry/float_box.h index 8365088b..24bc3c43 100644 --- a/third_party/blink/renderer/platform/geometry/float_box.h +++ b/third_party/blink/renderer/platform/geometry/float_box.h
@@ -42,12 +42,18 @@ DISALLOW_NEW(); public: - FloatBox() : x_(0), y_(0), z_(0), width_(0), height_(0), depth_(0) {} + constexpr FloatBox() + : x_(0), y_(0), z_(0), width_(0), height_(0), depth_(0) {} - FloatBox(float x, float y, float z, float width, float height, float depth) + constexpr FloatBox(float x, + float y, + float z, + float width, + float height, + float depth) : x_(x), y_(y), z_(z), width_(width), height_(height), depth_(depth) {} - FloatBox(const FloatBox& box) + constexpr FloatBox(const FloatBox& box) : x_(box.X()), y_(box.Y()), z_(box.Z()), @@ -102,20 +108,20 @@ ExpandTo(box); } - bool IsEmpty() const { + constexpr bool IsEmpty() const { return (width_ <= 0 && height_ <= 0) || (width_ <= 0 && depth_ <= 0) || (height_ <= 0 && depth_ <= 0); } - float Right() const { return x_ + width_; } - float Bottom() const { return y_ + height_; } - float front() const { return z_ + depth_; } - float X() const { return x_; } - float Y() const { return y_; } - float Z() const { return z_; } - float Width() const { return width_; } - float Height() const { return height_; } - float Depth() const { return depth_; } + constexpr float Right() const { return x_ + width_; } + constexpr float Bottom() const { return y_ + height_; } + constexpr float front() const { return z_ + depth_; } + constexpr float X() const { return x_; } + constexpr float Y() const { return y_; } + constexpr float Z() const { return z_; } + constexpr float Width() const { return width_; } + constexpr float Height() const { return height_; } + constexpr float Depth() const { return depth_; } String ToString() const; @@ -128,13 +134,13 @@ float depth_; }; -inline bool operator==(const FloatBox& a, const FloatBox& b) { +constexpr bool operator==(const FloatBox& a, const FloatBox& b) { return a.X() == b.X() && a.Y() == b.Y() && a.Z() == b.Z() && a.Width() == b.Width() && a.Height() == b.Height() && a.Depth() == b.Depth(); } -inline bool operator!=(const FloatBox& a, const FloatBox& b) { +constexpr bool operator!=(const FloatBox& a, const FloatBox& b) { return !(a == b); }
diff --git a/third_party/blink/renderer/platform/geometry/float_point.h b/third_party/blink/renderer/platform/geometry/float_point.h index e2f0565..6aaa4ef 100644 --- a/third_party/blink/renderer/platform/geometry/float_point.h +++ b/third_party/blink/renderer/platform/geometry/float_point.h
@@ -62,24 +62,24 @@ DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: - FloatPoint() : x_(0), y_(0) {} - FloatPoint(float x, float y) : x_(x), y_(y) {} + constexpr FloatPoint() : x_(0), y_(0) {} + constexpr FloatPoint(float x, float y) : x_(x), y_(y) {} explicit FloatPoint(const IntPoint&); explicit FloatPoint(const SkPoint&); explicit FloatPoint(const DoublePoint&); explicit FloatPoint(const LayoutPoint&); - explicit FloatPoint(const FloatSize& size) + constexpr explicit FloatPoint(const FloatSize& size) : x_(size.Width()), y_(size.Height()) {} explicit FloatPoint(const LayoutSize&); - explicit FloatPoint(const IntSize& size) + constexpr explicit FloatPoint(const IntSize& size) : x_(size.Width()), y_(size.Height()) {} - static FloatPoint Zero() { return FloatPoint(); } + static constexpr FloatPoint Zero() { return FloatPoint(); } static FloatPoint NarrowPrecision(double x, double y); - float X() const { return x_; } - float Y() const { return y_; } + constexpr float X() const { return x_; } + constexpr float Y() const { return y_; } void SetX(float x) { x_ = x; } void SetY(float y) { y_ = y; } @@ -159,48 +159,48 @@ return a; } -inline FloatPoint operator+(const FloatPoint& a, const FloatSize& b) { +constexpr FloatPoint operator+(const FloatPoint& a, const FloatSize& b) { return FloatPoint(a.X() + b.Width(), a.Y() + b.Height()); } -inline FloatPoint operator+(const FloatPoint& a, const IntSize& b) { +constexpr FloatPoint operator+(const FloatPoint& a, const IntSize& b) { return FloatPoint(a.X() + b.Width(), a.Y() + b.Height()); } -inline FloatPoint operator+(const IntPoint& a, const FloatSize& b) { +constexpr FloatPoint operator+(const IntPoint& a, const FloatSize& b) { return FloatPoint(a.X() + b.Width(), a.Y() + b.Height()); } -inline FloatPoint operator+(const FloatPoint& a, const FloatPoint& b) { +constexpr FloatPoint operator+(const FloatPoint& a, const FloatPoint& b) { return FloatPoint(a.X() + b.X(), a.Y() + b.Y()); } -inline FloatPoint operator+(const FloatPoint& a, const IntPoint& b) { +constexpr FloatPoint operator+(const FloatPoint& a, const IntPoint& b) { return FloatPoint(a.X() + b.X(), a.Y() + b.Y()); } -inline FloatSize operator-(const FloatPoint& a, const FloatPoint& b) { +constexpr FloatSize operator-(const FloatPoint& a, const FloatPoint& b) { return FloatSize(a.X() - b.X(), a.Y() - b.Y()); } -inline FloatSize operator-(const FloatPoint& a, const IntPoint& b) { +constexpr FloatSize operator-(const FloatPoint& a, const IntPoint& b) { return FloatSize(a.X() - b.X(), a.Y() - b.Y()); } -inline FloatPoint operator-(const FloatPoint& a, const FloatSize& b) { +constexpr FloatPoint operator-(const FloatPoint& a, const FloatSize& b) { return FloatPoint(a.X() - b.Width(), a.Y() - b.Height()); } -inline FloatPoint operator-(const FloatPoint& a) { +constexpr FloatPoint operator-(const FloatPoint& a) { return FloatPoint(-a.X(), -a.Y()); } -inline bool operator==(const FloatPoint& a, const FloatPoint& b) { +constexpr bool operator==(const FloatPoint& a, const FloatPoint& b) { return a.X() == b.X() && a.Y() == b.Y(); } -inline bool operator!=(const FloatPoint& a, const FloatPoint& b) { - return a.X() != b.X() || a.Y() != b.Y(); +constexpr bool operator!=(const FloatPoint& a, const FloatPoint& b) { + return !(a == b); } inline float operator*(const FloatPoint& a, const FloatPoint& b) {
diff --git a/third_party/blink/renderer/platform/geometry/float_point_3d.h b/third_party/blink/renderer/platform/geometry/float_point_3d.h index 6717f3f1..9083de7 100644 --- a/third_party/blink/renderer/platform/geometry/float_point_3d.h +++ b/third_party/blink/renderer/platform/geometry/float_point_3d.h
@@ -38,21 +38,22 @@ DISALLOW_NEW(); public: - FloatPoint3D() : x_(0), y_(0), z_(0) {} + constexpr FloatPoint3D() : x_(0), y_(0), z_(0) {} - FloatPoint3D(float x, float y, float z) : x_(x), y_(y), z_(z) {} + constexpr FloatPoint3D(float x, float y, float z) : x_(x), y_(y), z_(z) {} - FloatPoint3D(const FloatPoint& p) : x_(p.X()), y_(p.Y()), z_(0) {} + constexpr FloatPoint3D(const FloatPoint& p) : x_(p.X()), y_(p.Y()), z_(0) {} - FloatPoint3D(const FloatPoint3D& p) : x_(p.X()), y_(p.Y()), z_(p.Z()) {} + constexpr FloatPoint3D(const FloatPoint3D& p) + : x_(p.X()), y_(p.Y()), z_(p.Z()) {} - float X() const { return x_; } + constexpr float X() const { return x_; } void SetX(float x) { x_ = x; } - float Y() const { return y_; } + constexpr float Y() const { return y_; } void SetY(float y) { y_ = y; } - float Z() const { return z_; } + constexpr float Z() const { return z_; } void SetZ(float z) { z_ = z; } void Set(float x, float y, float z) { x_ = x; @@ -70,7 +71,7 @@ z_ *= sz; } - bool IsZero() const { return !x_ && !y_ && !z_; } + constexpr bool IsZero() const { return !x_ && !y_ && !z_; } void Normalize(); @@ -128,20 +129,20 @@ return a; } -inline FloatPoint3D operator+(const FloatPoint3D& a, const FloatPoint3D& b) { +constexpr FloatPoint3D operator+(const FloatPoint3D& a, const FloatPoint3D& b) { return FloatPoint3D(a.X() + b.X(), a.Y() + b.Y(), a.Z() + b.Z()); } -inline FloatPoint3D operator-(const FloatPoint3D& a, const FloatPoint3D& b) { +constexpr FloatPoint3D operator-(const FloatPoint3D& a, const FloatPoint3D& b) { return FloatPoint3D(a.X() - b.X(), a.Y() - b.Y(), a.Z() - b.Z()); } -inline bool operator==(const FloatPoint3D& a, const FloatPoint3D& b) { +constexpr bool operator==(const FloatPoint3D& a, const FloatPoint3D& b) { return a.X() == b.X() && a.Y() == b.Y() && a.Z() == b.Z(); } -inline bool operator!=(const FloatPoint3D& a, const FloatPoint3D& b) { - return a.X() != b.X() || a.Y() != b.Y() || a.Z() != b.Z(); +constexpr bool operator!=(const FloatPoint3D& a, const FloatPoint3D& b) { + return !(a == b); } inline float operator*(const FloatPoint3D& a, const FloatPoint3D& b) {
diff --git a/third_party/blink/renderer/platform/geometry/float_quad.h b/third_party/blink/renderer/platform/geometry/float_quad.h index 26922ce..a2e632e 100644 --- a/third_party/blink/renderer/platform/geometry/float_quad.h +++ b/third_party/blink/renderer/platform/geometry/float_quad.h
@@ -47,15 +47,15 @@ USING_FAST_MALLOC(FloatQuad); public: - FloatQuad() = default; + constexpr FloatQuad() = default; - FloatQuad(const FloatPoint& p1, - const FloatPoint& p2, - const FloatPoint& p3, - const FloatPoint& p4) + constexpr FloatQuad(const FloatPoint& p1, + const FloatPoint& p2, + const FloatPoint& p3, + const FloatPoint& p4) : p1_(p1), p2_(p2), p3_(p3), p4_(p4) {} - FloatQuad(const FloatRect& in_rect) + constexpr FloatQuad(const FloatRect& in_rect) : p1_(in_rect.Location()), p2_(in_rect.MaxX(), in_rect.Y()), p3_(in_rect.MaxX(), in_rect.MaxY()), @@ -174,14 +174,13 @@ return a; } -inline bool operator==(const FloatQuad& a, const FloatQuad& b) { +constexpr bool operator==(const FloatQuad& a, const FloatQuad& b) { return a.P1() == b.P1() && a.P2() == b.P2() && a.P3() == b.P3() && a.P4() == b.P4(); } -inline bool operator!=(const FloatQuad& a, const FloatQuad& b) { - return a.P1() != b.P1() || a.P2() != b.P2() || a.P3() != b.P3() || - a.P4() != b.P4(); +constexpr bool operator!=(const FloatQuad& a, const FloatQuad& b) { + return !(a == b); } PLATFORM_EXPORT std::ostream& operator<<(std::ostream&, const FloatQuad&);
diff --git a/third_party/blink/renderer/platform/geometry/float_rect.h b/third_party/blink/renderer/platform/geometry/float_rect.h index 3434286..b677554 100644 --- a/third_party/blink/renderer/platform/geometry/float_rect.h +++ b/third_party/blink/renderer/platform/geometry/float_rect.h
@@ -62,10 +62,10 @@ public: enum ContainsMode { kInsideOrOnStroke, kInsideButNotOnStroke }; - FloatRect() = default; - FloatRect(const FloatPoint& location, const FloatSize& size) + constexpr FloatRect() = default; + constexpr FloatRect(const FloatPoint& location, const FloatSize& size) : location_(location), size_(size) {} - FloatRect(float x, float y, float width, float height) + constexpr FloatRect(float x, float y, float width, float height) : location_(FloatPoint(x, y)), size_(FloatSize(width, height)) {} explicit FloatRect(const IntRect&); explicit FloatRect(const LayoutRect&); @@ -76,26 +76,26 @@ double width, double height); - FloatPoint Location() const { return location_; } - FloatSize Size() const { return size_; } + constexpr FloatPoint Location() const { return location_; } + constexpr FloatSize Size() const { return size_; } void SetLocation(const FloatPoint& location) { location_ = location; } void SetSize(const FloatSize& size) { size_ = size; } - float X() const { return location_.X(); } - float Y() const { return location_.Y(); } - float MaxX() const { return X() + Width(); } - float MaxY() const { return Y() + Height(); } - float Width() const { return size_.Width(); } - float Height() const { return size_.Height(); } + constexpr float X() const { return location_.X(); } + constexpr float Y() const { return location_.Y(); } + constexpr float MaxX() const { return X() + Width(); } + constexpr float MaxY() const { return Y() + Height(); } + constexpr float Width() const { return size_.Width(); } + constexpr float Height() const { return size_.Height(); } void SetX(float x) { location_.SetX(x); } void SetY(float y) { location_.SetY(y); } void SetWidth(float width) { size_.SetWidth(width); } void SetHeight(float height) { size_.SetHeight(height); } - bool IsEmpty() const { return size_.IsEmpty(); } - bool IsZero() const { return size_.IsZero(); } + constexpr bool IsEmpty() const { return size_.IsEmpty(); } + constexpr bool IsZero() const { return size_.IsZero(); } bool IsExpressibleAsIntRect() const; FloatPoint Center() const { @@ -235,18 +235,16 @@ return a; } -inline FloatRect operator+(const FloatRect& a, const FloatRect& b) { - FloatRect c = a; - c += b; - return c; +constexpr FloatRect operator+(const FloatRect& a, const FloatRect& b) { + return FloatRect(a.Location() + b.Location(), a.Size() + b.Size()); } -inline bool operator==(const FloatRect& a, const FloatRect& b) { +constexpr bool operator==(const FloatRect& a, const FloatRect& b) { return a.Location() == b.Location() && a.Size() == b.Size(); } -inline bool operator!=(const FloatRect& a, const FloatRect& b) { - return a.Location() != b.Location() || a.Size() != b.Size(); +constexpr bool operator!=(const FloatRect& a, const FloatRect& b) { + return !(a == b); } // Returns a IntRect containing the given FloatRect.
diff --git a/third_party/blink/renderer/platform/geometry/float_rect_outsets.h b/third_party/blink/renderer/platform/geometry/float_rect_outsets.h index 6d809ad..ef8c31a9 100644 --- a/third_party/blink/renderer/platform/geometry/float_rect_outsets.h +++ b/third_party/blink/renderer/platform/geometry/float_rect_outsets.h
@@ -19,15 +19,15 @@ STACK_ALLOCATED(); public: - FloatRectOutsets() : top_(0), right_(0), bottom_(0), left_(0) {} + constexpr FloatRectOutsets() : top_(0), right_(0), bottom_(0), left_(0) {} - FloatRectOutsets(float top, float right, float bottom, float left) + constexpr FloatRectOutsets(float top, float right, float bottom, float left) : top_(top), right_(right), bottom_(bottom), left_(left) {} - float Top() const { return top_; } - float Right() const { return right_; } - float Bottom() const { return bottom_; } - float Left() const { return left_; } + constexpr float Top() const { return top_; } + constexpr float Right() const { return right_; } + constexpr float Bottom() const { return bottom_; } + constexpr float Left() const { return left_; } void SetTop(float top) { top_ = top; } void SetRight(float right) { right_ = right; }
diff --git a/third_party/blink/renderer/platform/geometry/float_rounded_rect.h b/third_party/blink/renderer/platform/geometry/float_rounded_rect.h index edd2c53..877f9f6 100644 --- a/third_party/blink/renderer/platform/geometry/float_rounded_rect.h +++ b/third_party/blink/renderer/platform/geometry/float_rounded_rect.h
@@ -48,17 +48,17 @@ DISALLOW_NEW(); public: - Radii() = default; - Radii(const FloatSize& top_left, - const FloatSize& top_right, - const FloatSize& bottom_left, - const FloatSize& bottom_right) + constexpr Radii() = default; + constexpr Radii(const FloatSize& top_left, + const FloatSize& top_right, + const FloatSize& bottom_left, + const FloatSize& bottom_right) : top_left_(top_left), top_right_(top_right), bottom_left_(bottom_left), bottom_right_(bottom_right) {} - Radii(const FloatRoundedRect::Radii& int_radii) + constexpr Radii(const FloatRoundedRect::Radii& int_radii) : top_left_(int_radii.TopLeft()), top_right_(int_radii.TopRight()), bottom_left_(int_radii.BottomLeft()), @@ -68,12 +68,12 @@ void SetTopRight(const FloatSize& size) { top_right_ = size; } void SetBottomLeft(const FloatSize& size) { bottom_left_ = size; } void SetBottomRight(const FloatSize& size) { bottom_right_ = size; } - const FloatSize& TopLeft() const { return top_left_; } - const FloatSize& TopRight() const { return top_right_; } - const FloatSize& BottomLeft() const { return bottom_left_; } - const FloatSize& BottomRight() const { return bottom_right_; } + constexpr const FloatSize& TopLeft() const { return top_left_; } + constexpr const FloatSize& TopRight() const { return top_right_; } + constexpr const FloatSize& BottomLeft() const { return bottom_left_; } + constexpr const FloatSize& BottomRight() const { return bottom_right_; } - bool IsZero() const { + constexpr bool IsZero() const { return top_left_.IsZero() && top_right_.IsZero() && bottom_left_.IsZero() && bottom_right_.IsZero(); } @@ -109,7 +109,7 @@ FloatSize bottom_right_; }; - FloatRoundedRect() = default; + constexpr FloatRoundedRect() = default; explicit FloatRoundedRect(const FloatRect&, const Radii& = Radii()); explicit FloatRoundedRect(const IntRect&, const Radii& = Radii()); FloatRoundedRect(float x, float y, float width, float height); @@ -119,10 +119,10 @@ const FloatSize& bottom_left, const FloatSize& bottom_right); - const FloatRect& Rect() const { return rect_; } - const Radii& GetRadii() const { return radii_; } - bool IsRounded() const { return !radii_.IsZero(); } - bool IsEmpty() const { return rect_.IsEmpty(); } + constexpr const FloatRect& Rect() const { return rect_; } + constexpr const Radii& GetRadii() const { return radii_; } + constexpr bool IsRounded() const { return !radii_.IsZero(); } + constexpr bool IsEmpty() const { return rect_.IsEmpty(); } void SetRect(const FloatRect& rect) { rect_ = rect; } void SetRadii(const Radii& radii) { radii_ = radii; } @@ -141,19 +141,19 @@ // Returns a quickly computed rect enclosed by the rounded rect. FloatRect RadiusCenterRect() const; - FloatRect TopLeftCorner() const { + constexpr FloatRect TopLeftCorner() const { return FloatRect(rect_.X(), rect_.Y(), radii_.TopLeft().Width(), radii_.TopLeft().Height()); } - FloatRect TopRightCorner() const { + constexpr FloatRect TopRightCorner() const { return FloatRect(rect_.MaxX() - radii_.TopRight().Width(), rect_.Y(), radii_.TopRight().Width(), radii_.TopRight().Height()); } - FloatRect BottomLeftCorner() const { + constexpr FloatRect BottomLeftCorner() const { return FloatRect(rect_.X(), rect_.MaxY() - radii_.BottomLeft().Height(), radii_.BottomLeft().Width(), radii_.BottomLeft().Height()); } - FloatRect BottomRightCorner() const { + constexpr FloatRect BottomRightCorner() const { return FloatRect(rect_.MaxX() - radii_.BottomRight().Width(), rect_.MaxY() - radii_.BottomRight().Height(), radii_.BottomRight().Width(), @@ -218,22 +218,24 @@ return rrect; } -inline bool operator==(const FloatRoundedRect::Radii& a, - const FloatRoundedRect::Radii& b) { +constexpr bool operator==(const FloatRoundedRect::Radii& a, + const FloatRoundedRect::Radii& b) { return a.TopLeft() == b.TopLeft() && a.TopRight() == b.TopRight() && a.BottomLeft() == b.BottomLeft() && a.BottomRight() == b.BottomRight(); } -inline bool operator!=(const FloatRoundedRect::Radii& a, - const FloatRoundedRect::Radii& b) { +constexpr bool operator!=(const FloatRoundedRect::Radii& a, + const FloatRoundedRect::Radii& b) { return !(a == b); } -inline bool operator==(const FloatRoundedRect& a, const FloatRoundedRect& b) { +constexpr bool operator==(const FloatRoundedRect& a, + const FloatRoundedRect& b) { return a.Rect() == b.Rect() && a.GetRadii() == b.GetRadii(); } -inline bool operator!=(const FloatRoundedRect& a, const FloatRoundedRect& b) { +constexpr bool operator!=(const FloatRoundedRect& a, + const FloatRoundedRect& b) { return !(a == b); }
diff --git a/third_party/blink/renderer/platform/geometry/float_size.h b/third_party/blink/renderer/platform/geometry/float_size.h index faf4827..d8e53d6 100644 --- a/third_party/blink/renderer/platform/geometry/float_size.h +++ b/third_party/blink/renderer/platform/geometry/float_size.h
@@ -34,6 +34,7 @@ #include "third_party/blink/renderer/platform/geometry/int_point.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/forward.h" +#include "third_party/blink/renderer/platform/wtf/math_extras.h" #if defined(OS_MACOSX) typedef struct CGSize CGSize; @@ -59,8 +60,9 @@ DISALLOW_NEW(); public: - FloatSize() : width_(0), height_(0) {} - FloatSize(float width, float height) : width_(width), height_(height) {} + constexpr FloatSize() : width_(0), height_(0) {} + constexpr FloatSize(float width, float height) + : width_(width), height_(height) {} explicit FloatSize(const IntSize& size) : width_(size.Width()), height_(size.Height()) {} FloatSize(const SkSize&); @@ -68,13 +70,13 @@ static FloatSize NarrowPrecision(double width, double height); - float Width() const { return width_; } - float Height() const { return height_; } + constexpr float Width() const { return width_; } + constexpr float Height() const { return height_; } void SetWidth(float width) { width_ = width; } void SetHeight(float height) { height_ = height; } - bool IsEmpty() const { return width_ <= 0 || height_ <= 0; } + constexpr bool IsEmpty() const { return width_ <= 0 || height_ <= 0; } bool IsZero() const { return fabs(width_) < std::numeric_limits<float>::epsilon() && fabs(height_) < std::numeric_limits<float>::epsilon(); @@ -153,38 +155,38 @@ return a; } -inline FloatSize& operator-=(FloatSize& a, const FloatSize& b) { +constexpr FloatSize& operator-=(FloatSize& a, const FloatSize& b) { a.SetWidth(a.Width() - b.Width()); a.SetHeight(a.Height() - b.Height()); return a; } -inline FloatSize operator+(const FloatSize& a, const FloatSize& b) { +constexpr FloatSize operator+(const FloatSize& a, const FloatSize& b) { return FloatSize(a.Width() + b.Width(), a.Height() + b.Height()); } -inline FloatSize operator-(const FloatSize& a, const FloatSize& b) { +constexpr FloatSize operator-(const FloatSize& a, const FloatSize& b) { return FloatSize(a.Width() - b.Width(), a.Height() - b.Height()); } -inline FloatSize operator-(const FloatSize& size) { +constexpr FloatSize operator-(const FloatSize& size) { return FloatSize(-size.Width(), -size.Height()); } -inline FloatSize operator*(const FloatSize& a, const float b) { +constexpr FloatSize operator*(const FloatSize& a, const float b) { return FloatSize(a.Width() * b, a.Height() * b); } -inline FloatSize operator*(const float a, const FloatSize& b) { +constexpr FloatSize operator*(const float a, const FloatSize& b) { return FloatSize(a * b.Width(), a * b.Height()); } -inline bool operator==(const FloatSize& a, const FloatSize& b) { +constexpr bool operator==(const FloatSize& a, const FloatSize& b) { return a.Width() == b.Width() && a.Height() == b.Height(); } -inline bool operator!=(const FloatSize& a, const FloatSize& b) { - return a.Width() != b.Width() || a.Height() != b.Height(); +constexpr bool operator!=(const FloatSize& a, const FloatSize& b) { + return !(a == b); } inline IntSize RoundedIntSize(const FloatSize& p) {
diff --git a/third_party/blink/renderer/platform/geometry/int_point.h b/third_party/blink/renderer/platform/geometry/int_point.h index 95b7daf..5da33140 100644 --- a/third_party/blink/renderer/platform/geometry/int_point.h +++ b/third_party/blink/renderer/platform/geometry/int_point.h
@@ -54,15 +54,15 @@ USING_FAST_MALLOC(IntPoint); public: - IntPoint() : x_(0), y_(0) {} - IntPoint(int x, int y) : x_(x), y_(y) {} + constexpr IntPoint() : x_(0), y_(0) {} + constexpr IntPoint(int x, int y) : x_(x), y_(y) {} explicit IntPoint(const IntSize& size) : x_(size.Width()), y_(size.Height()) {} static IntPoint Zero() { return IntPoint(); } - int X() const { return x_; } - int Y() const { return y_; } + constexpr int X() const { return x_; } + constexpr int Y() const { return y_; } void SetX(int x) { x_ = x; } void SetY(int y) { y_ = y; } @@ -126,32 +126,32 @@ return a; } -inline IntPoint operator+(const IntPoint& a, const IntSize& b) { +constexpr IntPoint operator+(const IntPoint& a, const IntSize& b) { return IntPoint(a.X() + b.Width(), a.Y() + b.Height()); } -inline IntPoint operator+(const IntPoint& a, const IntPoint& b) { +constexpr IntPoint operator+(const IntPoint& a, const IntPoint& b) { return IntPoint(a.X() + b.X(), a.Y() + b.Y()); } -inline IntSize operator-(const IntPoint& a, const IntPoint& b) { +constexpr IntSize operator-(const IntPoint& a, const IntPoint& b) { return IntSize(a.X() - b.X(), a.Y() - b.Y()); } -inline IntPoint operator-(const IntPoint& a, const IntSize& b) { +constexpr IntPoint operator-(const IntPoint& a, const IntSize& b) { return IntPoint(a.X() - b.Width(), a.Y() - b.Height()); } -inline IntPoint operator-(const IntPoint& point) { +constexpr IntPoint operator-(const IntPoint& point) { return IntPoint(-point.X(), -point.Y()); } -inline bool operator==(const IntPoint& a, const IntPoint& b) { +constexpr bool operator==(const IntPoint& a, const IntPoint& b) { return a.X() == b.X() && a.Y() == b.Y(); } -inline bool operator!=(const IntPoint& a, const IntPoint& b) { - return a.X() != b.X() || a.Y() != b.Y(); +constexpr bool operator!=(const IntPoint& a, const IntPoint& b) { + return !(a == b); } inline IntSize ToIntSize(const IntPoint& a) {
diff --git a/third_party/blink/renderer/platform/geometry/int_rect.h b/third_party/blink/renderer/platform/geometry/int_rect.h index e9d86bf8..6d07e19 100644 --- a/third_party/blink/renderer/platform/geometry/int_rect.h +++ b/third_party/blink/renderer/platform/geometry/int_rect.h
@@ -58,38 +58,38 @@ USING_FAST_MALLOC(IntRect); public: - IntRect() = default; - IntRect(const IntPoint& location, const IntSize& size) + constexpr IntRect() = default; + constexpr IntRect(const IntPoint& location, const IntSize& size) : location_(location), size_(size) {} - IntRect(int x, int y, int width, int height) + constexpr IntRect(int x, int y, int width, int height) : location_(IntPoint(x, y)), size_(IntSize(width, height)) {} // Use EnclosingIntRect(), EnclosedIntRect(), RoundedIntRect(), // PixelSnappedIntRect(), etc. instead. - explicit IntRect(const FloatRect&) = delete; - explicit IntRect(const LayoutRect&) = delete; + constexpr explicit IntRect(const FloatRect&) = delete; + constexpr explicit IntRect(const LayoutRect&) = delete; explicit IntRect(const gfx::Rect& rect); - IntPoint Location() const { return location_; } - IntSize Size() const { return size_; } + constexpr IntPoint Location() const { return location_; } + constexpr IntSize Size() const { return size_; } void SetLocation(const IntPoint& location) { location_ = location; } void SetSize(const IntSize& size) { size_ = size; } - int X() const { return location_.X(); } - int Y() const { return location_.Y(); } - int MaxX() const { return X() + Width(); } - int MaxY() const { return Y() + Height(); } - int Width() const { return size_.Width(); } - int Height() const { return size_.Height(); } + constexpr int X() const { return location_.X(); } + constexpr int Y() const { return location_.Y(); } + constexpr int MaxX() const { return X() + Width(); } + constexpr int MaxY() const { return Y() + Height(); } + constexpr int Width() const { return size_.Width(); } + constexpr int Height() const { return size_.Height(); } void SetX(int x) { location_.SetX(x); } void SetY(int y) { location_.SetY(y); } void SetWidth(int width) { size_.SetWidth(width); } void SetHeight(int height) { size_.SetHeight(height); } - bool IsEmpty() const { return size_.IsEmpty(); } + constexpr bool IsEmpty() const { return size_.IsEmpty(); } // NOTE: The result is rounded to integer values, and thus may be not the // exact center point. @@ -120,14 +120,16 @@ void ShiftYEdgeTo(int); void ShiftMaxYEdgeTo(int); - IntPoint MinXMinYCorner() const { return location_; } // typically topLeft - IntPoint MaxXMinYCorner() const { + constexpr IntPoint MinXMinYCorner() const { + return location_; + } // typically topLeft + constexpr IntPoint MaxXMinYCorner() const { return IntPoint(location_.X() + size_.Width(), location_.Y()); } // typically topRight - IntPoint MinXMaxYCorner() const { + constexpr IntPoint MinXMaxYCorner() const { return IntPoint(location_.X(), location_.Y() + size_.Height()); } // typically bottomLeft - IntPoint MaxXMaxYCorner() const { + constexpr IntPoint MaxXMaxYCorner() const { return IntPoint(location_.X() + size_.Width(), location_.Y() + size_.Height()); } // typically bottomRight @@ -218,17 +220,17 @@ PLATFORM_EXPORT IntRect UnionRectEvenIfEmpty(const Vector<IntRect>&); -inline IntRect SaturatedRect(const IntRect& r) { +constexpr IntRect SaturatedRect(const IntRect& r) { return IntRect(r.X(), r.Y(), ClampAdd(r.X(), r.Width()) - r.X(), ClampAdd(r.Y(), r.Height()) - r.Y()); } -inline bool operator==(const IntRect& a, const IntRect& b) { +constexpr bool operator==(const IntRect& a, const IntRect& b) { return a.Location() == b.Location() && a.Size() == b.Size(); } -inline bool operator!=(const IntRect& a, const IntRect& b) { - return a.Location() != b.Location() || a.Size() != b.Size(); +constexpr bool operator!=(const IntRect& a, const IntRect& b) { + return !(a == b); } PLATFORM_EXPORT std::ostream& operator<<(std::ostream&, const IntRect&);
diff --git a/third_party/blink/renderer/platform/geometry/int_rect_outsets.h b/third_party/blink/renderer/platform/geometry/int_rect_outsets.h index a5e4689..30ccf48 100644 --- a/third_party/blink/renderer/platform/geometry/int_rect_outsets.h +++ b/third_party/blink/renderer/platform/geometry/int_rect_outsets.h
@@ -44,22 +44,24 @@ DISALLOW_NEW(); public: - IntRectOutsets() : top_(0), right_(0), bottom_(0), left_(0) {} + constexpr IntRectOutsets() : top_(0), right_(0), bottom_(0), left_(0) {} - IntRectOutsets(int top, int right, int bottom, int left) + constexpr IntRectOutsets(int top, int right, int bottom, int left) : top_(top), right_(right), bottom_(bottom), left_(left) {} - int Top() const { return top_; } - int Right() const { return right_; } - int Bottom() const { return bottom_; } - int Left() const { return left_; } + constexpr int Top() const { return top_; } + constexpr int Right() const { return right_; } + constexpr int Bottom() const { return bottom_; } + constexpr int Left() const { return left_; } void SetTop(int top) { top_ = top; } void SetRight(int right) { right_ = right; } void SetBottom(int bottom) { bottom_ = bottom; } void SetLeft(int left) { left_ = left; } - bool IsZero() const { return !Left() && !Right() && !Top() && !Bottom(); } + constexpr bool IsZero() const { + return !Left() && !Right() && !Top() && !Bottom(); + } private: int top_;
diff --git a/third_party/blink/renderer/platform/geometry/int_size.h b/third_party/blink/renderer/platform/geometry/int_size.h index ca7913e..a67d575 100644 --- a/third_party/blink/renderer/platform/geometry/int_size.h +++ b/third_party/blink/renderer/platform/geometry/int_size.h
@@ -53,18 +53,18 @@ DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: - IntSize() : width_(0), height_(0) {} - IntSize(int width, int height) : width_(width), height_(height) {} + constexpr IntSize() : width_(0), height_(0) {} + constexpr IntSize(int width, int height) : width_(width), height_(height) {} explicit IntSize(const gfx::Size&); - int Width() const { return width_; } - int Height() const { return height_; } + constexpr int Width() const { return width_; } + constexpr int Height() const { return height_; } void SetWidth(int width) { width_ = width; } void SetHeight(int height) { height_ = height; } - bool IsEmpty() const { return width_ <= 0 || height_ <= 0; } - bool IsZero() const { return !width_ && !height_; } + constexpr bool IsEmpty() const { return width_ <= 0 || height_ <= 0; } + constexpr bool IsZero() const { return !width_ && !height_; } float AspectRatio() const { return static_cast<float>(width_) / static_cast<float>(height_);
diff --git a/third_party/blink/renderer/platform/geometry/layout_point.h b/third_party/blink/renderer/platform/geometry/layout_point.h index 10726fb7..2f3c1be 100644 --- a/third_party/blink/renderer/platform/geometry/layout_point.h +++ b/third_party/blink/renderer/platform/geometry/layout_point.h
@@ -44,21 +44,21 @@ DISALLOW_NEW(); public: - LayoutPoint() = default; - LayoutPoint(LayoutUnit x, LayoutUnit y) : x_(x), y_(y) {} + constexpr LayoutPoint() = default; + constexpr LayoutPoint(LayoutUnit x, LayoutUnit y) : x_(x), y_(y) {} LayoutPoint(int x, int y) : x_(LayoutUnit(x)), y_(LayoutUnit(y)) {} LayoutPoint(const IntPoint& point) : x_(point.X()), y_(point.Y()) {} explicit LayoutPoint(const FloatPoint& point) : x_(point.X()), y_(point.Y()) {} explicit LayoutPoint(const DoublePoint& point) : x_(point.X()), y_(point.Y()) {} - explicit LayoutPoint(const LayoutSize& size) + constexpr explicit LayoutPoint(const LayoutSize& size) : x_(size.Width()), y_(size.Height()) {} - static LayoutPoint Zero() { return LayoutPoint(); } + static constexpr LayoutPoint Zero() { return LayoutPoint(); } - LayoutUnit X() const { return x_; } - LayoutUnit Y() const { return y_; } + constexpr LayoutUnit X() const { return x_; } + constexpr LayoutUnit Y() const { return y_; } void SetX(LayoutUnit x) { x_ = x; } void SetY(LayoutUnit y) { y_ = y; } @@ -148,23 +148,24 @@ return LayoutPoint(-point.X(), -point.Y()); } -ALWAYS_INLINE bool operator==(const LayoutPoint& a, const LayoutPoint& b) { +constexpr ALWAYS_INLINE bool operator==(const LayoutPoint& a, + const LayoutPoint& b) { return a.X() == b.X() && a.Y() == b.Y(); } -inline bool operator!=(const LayoutPoint& a, const LayoutPoint& b) { - return a.X() != b.X() || a.Y() != b.Y(); +constexpr bool operator!=(const LayoutPoint& a, const LayoutPoint& b) { + return !(a == b); } -inline LayoutPoint ToPoint(const LayoutSize& size) { +constexpr inline LayoutPoint ToPoint(const LayoutSize& size) { return LayoutPoint(size.Width(), size.Height()); } -inline LayoutPoint ToLayoutPoint(const LayoutSize& p) { +constexpr inline LayoutPoint ToLayoutPoint(const LayoutSize& p) { return LayoutPoint(p.Width(), p.Height()); } -inline LayoutSize ToSize(const LayoutPoint& a) { +constexpr inline LayoutSize ToSize(const LayoutPoint& a) { return LayoutSize(a.X(), a.Y()); }
diff --git a/third_party/blink/renderer/platform/geometry/layout_rect.h b/third_party/blink/renderer/platform/geometry/layout_rect.h index e05e54d..c3dd51b 100644 --- a/third_party/blink/renderer/platform/geometry/layout_rect.h +++ b/third_party/blink/renderer/platform/geometry/layout_rect.h
@@ -48,10 +48,13 @@ DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: - LayoutRect() = default; - LayoutRect(const LayoutPoint& location, const LayoutSize& size) + constexpr LayoutRect() = default; + constexpr LayoutRect(const LayoutPoint& location, const LayoutSize& size) : location_(location), size_(size) {} - LayoutRect(LayoutUnit x, LayoutUnit y, LayoutUnit width, LayoutUnit height) + constexpr LayoutRect(LayoutUnit x, + LayoutUnit y, + LayoutUnit width, + LayoutUnit height) : location_(LayoutPoint(x, y)), size_(LayoutSize(width, height)) {} LayoutRect(int x, int y, int width, int height) : location_(LayoutPoint(x, y)), size_(LayoutSize(width, height)) {} @@ -68,8 +71,8 @@ explicit LayoutRect(const FloatRect&); explicit LayoutRect(const DoubleRect&); - LayoutPoint Location() const { return location_; } - LayoutSize Size() const { return size_; } + constexpr LayoutPoint Location() const { return location_; } + constexpr LayoutSize Size() const { return size_; } IntPoint PixelSnappedLocation() const { return RoundedIntPoint(location_); } IntSize PixelSnappedSize() const { @@ -80,12 +83,12 @@ void SetLocation(const LayoutPoint& location) { location_ = location; } void SetSize(const LayoutSize& size) { size_ = size; } - ALWAYS_INLINE LayoutUnit X() const { return location_.X(); } - ALWAYS_INLINE LayoutUnit Y() const { return location_.Y(); } + constexpr ALWAYS_INLINE LayoutUnit X() const { return location_.X(); } + constexpr ALWAYS_INLINE LayoutUnit Y() const { return location_.Y(); } ALWAYS_INLINE LayoutUnit MaxX() const { return X() + Width(); } ALWAYS_INLINE LayoutUnit MaxY() const { return Y() + Height(); } - LayoutUnit Width() const { return size_.Width(); } - LayoutUnit Height() const { return size_.Height(); } + constexpr LayoutUnit Width() const { return size_.Width(); } + constexpr LayoutUnit Height() const { return size_.Height(); } int PixelSnappedWidth() const { return SnapSizeToPixel(Width(), X()); } int PixelSnappedHeight() const { return SnapSizeToPixel(Height(), Y()); } @@ -95,7 +98,7 @@ void SetWidth(LayoutUnit width) { size_.SetWidth(width); } void SetHeight(LayoutUnit height) { size_.SetHeight(height); } - ALWAYS_INLINE bool IsEmpty() const { return size_.IsEmpty(); } + constexpr ALWAYS_INLINE bool IsEmpty() const { return size_.IsEmpty(); } // NOTE: The result is rounded to integer values, and thus may be not the // exact center point. @@ -169,7 +172,9 @@ SetHeight((Height() + delta).ClampNegativeToZero()); } - LayoutPoint MinXMinYCorner() const { return location_; } // typically topLeft + constexpr LayoutPoint MinXMinYCorner() const { + return location_; + } // typically topLeft LayoutPoint MaxXMinYCorner() const { return LayoutPoint(location_.X() + size_.Width(), location_.Y()); } // typically topRight @@ -277,12 +282,13 @@ PLATFORM_EXPORT LayoutRect UnionRectEvenIfEmpty(const Vector<LayoutRect>&); -ALWAYS_INLINE bool operator==(const LayoutRect& a, const LayoutRect& b) { +constexpr ALWAYS_INLINE bool operator==(const LayoutRect& a, + const LayoutRect& b) { return a.Location() == b.Location() && a.Size() == b.Size(); } -inline bool operator!=(const LayoutRect& a, const LayoutRect& b) { - return a.Location() != b.Location() || a.Size() != b.Size(); +constexpr bool operator!=(const LayoutRect& a, const LayoutRect& b) { + return !(a == b); } inline IntRect PixelSnappedIntRect(const LayoutRect& rect) {
diff --git a/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h b/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h index 6086d2c..9f9c4bc 100644 --- a/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h +++ b/third_party/blink/renderer/platform/geometry/layout_rect_outsets.h
@@ -49,11 +49,11 @@ DISALLOW_NEW(); public: - LayoutRectOutsets() = default; - LayoutRectOutsets(LayoutUnit top, - LayoutUnit right, - LayoutUnit bottom, - LayoutUnit left) + constexpr LayoutRectOutsets() = default; + constexpr LayoutRectOutsets(LayoutUnit top, + LayoutUnit right, + LayoutUnit bottom, + LayoutUnit left) : top_(top), right_(right), bottom_(bottom), left_(left) {} LayoutRectOutsets(int top, int right, int bottom, int left) : top_(LayoutUnit(top)), @@ -73,10 +73,10 @@ bottom_(LayoutUnit(outsets.Bottom())), left_(LayoutUnit(outsets.Left())) {} - LayoutUnit Top() const { return top_; } - LayoutUnit Right() const { return right_; } - LayoutUnit Bottom() const { return bottom_; } - LayoutUnit Left() const { return left_; } + constexpr LayoutUnit Top() const { return top_; } + constexpr LayoutUnit Right() const { return right_; } + constexpr LayoutUnit Bottom() const { return bottom_; } + constexpr LayoutUnit Left() const { return left_; } void SetTop(LayoutUnit value) { top_ = value; } void SetRight(LayoutUnit value) { right_ = value; } @@ -84,7 +84,9 @@ void SetLeft(LayoutUnit value) { left_ = value; } LayoutSize Size() const { return LayoutSize(left_ + right_, top_ + bottom_); } - bool IsZero() const { return !top_ && !right_ && !bottom_ && !left_; } + constexpr bool IsZero() const { + return !top_ && !right_ && !bottom_ && !left_; + } void ClampNegativeToZero(); @@ -92,7 +94,7 @@ void FlipHorizontally() { std::swap(left_, right_); } - bool operator==(const LayoutRectOutsets other) const { + constexpr bool operator==(const LayoutRectOutsets other) const { return Top() == other.Top() && Right() == other.Right() && Bottom() == other.Bottom() && Left() == other.Left(); }
diff --git a/third_party/blink/renderer/platform/geometry/layout_size.h b/third_party/blink/renderer/platform/geometry/layout_size.h index 280ee87..e506382 100644 --- a/third_party/blink/renderer/platform/geometry/layout_size.h +++ b/third_party/blink/renderer/platform/geometry/layout_size.h
@@ -48,10 +48,10 @@ DISALLOW_NEW(); public: - LayoutSize() = default; + constexpr LayoutSize() = default; explicit LayoutSize(const IntSize& size) : width_(size.Width()), height_(size.Height()) {} - LayoutSize(LayoutUnit width, LayoutUnit height) + constexpr LayoutSize(LayoutUnit width, LayoutUnit height) : width_(width), height_(height) {} LayoutSize(int width, int height) : width_(LayoutUnit(width)), height_(LayoutUnit(height)) {} @@ -63,16 +63,16 @@ explicit LayoutSize(const DoubleSize& size) : width_(size.Width()), height_(size.Height()) {} - LayoutUnit Width() const { return width_; } - LayoutUnit Height() const { return height_; } + constexpr LayoutUnit Width() const { return width_; } + constexpr LayoutUnit Height() const { return height_; } void SetWidth(LayoutUnit width) { width_ = width; } void SetHeight(LayoutUnit height) { height_ = height; } - bool IsEmpty() const { + constexpr bool IsEmpty() const { return width_.RawValue() <= 0 || height_.RawValue() <= 0; } - bool IsZero() const { return !width_ && !height_; } + constexpr bool IsZero() const { return !width_ && !height_; } float AspectRatio() const { return width_.ToFloat() / height_.ToFloat(); } @@ -194,7 +194,7 @@ return LayoutSize(a.Width() * scale, a.Height() * scale); } -inline bool operator==(const LayoutSize& a, const LayoutSize& b) { +constexpr bool operator==(const LayoutSize& a, const LayoutSize& b) { return a.Width() == b.Width() && a.Height() == b.Height(); } @@ -202,15 +202,15 @@ return a.Width() == b.Width() && a.Height() == b.Height(); } -inline bool operator!=(const LayoutSize& a, const LayoutSize& b) { - return a.Width() != b.Width() || a.Height() != b.Height(); +constexpr bool operator!=(const LayoutSize& a, const LayoutSize& b) { + return !(a == b); } inline bool operator!=(const LayoutSize& a, const IntSize& b) { return a.Width() != b.Width() || a.Height() != b.Height(); } -inline FloatPoint operator+(const FloatPoint& a, const LayoutSize& b) { +constexpr FloatPoint operator+(const FloatPoint& a, const LayoutSize& b) { return FloatPoint(a.X() + b.Width(), a.Y() + b.Height()); }
diff --git a/third_party/blink/renderer/platform/geometry/layout_size_test.cc b/third_party/blink/renderer/platform/geometry/layout_size_test.cc index 2eb9e1ff..8c5e394 100644 --- a/third_party/blink/renderer/platform/geometry/layout_size_test.cc +++ b/third_party/blink/renderer/platform/geometry/layout_size_test.cc
@@ -18,7 +18,6 @@ .FitToAspectRatio(aspect_ratio, kAspectRatioFitShrink) .ToString()); - LayoutSize size(1000, 2000); EXPECT_EQ("1000x1000", LayoutSize(1000, 2000) .FitToAspectRatio(aspect_ratio, kAspectRatioFitShrink)
diff --git a/third_party/blink/renderer/platform/graphics/DEPS b/third_party/blink/renderer/platform/graphics/DEPS index 0ef1e730..af03830e 100644 --- a/third_party/blink/renderer/platform/graphics/DEPS +++ b/third_party/blink/renderer/platform/graphics/DEPS
@@ -3,18 +3,10 @@ "-third_party/blink/renderer/platform", # Module. - "+third_party/blink/renderer/platform/geometry", + "+third_party/blink/renderer/platform/graphics", # Dependencies. - "+base/bind.h", - "+base/callback.h", - "+base/compiler_specific.h", - "+base/message_loop", - "+base/task_runner.h", - "+base/task_runner_util.h", "+base/threading/sequenced_task_runner_handle.h", - "+base/threading/thread.h", - "+base/threading/thread_checker.h", "+cc", "+components/viz/client", "+components/viz/common", @@ -32,19 +24,18 @@ "+services/ui/public/cpp/gpu/context_provider_command_buffer.h", "+services/viz/public/interfaces", "+third_party/blink/renderer/platform/animation", - "+third_party/blink/renderer/platform/bindings/runtime_call_stats.h", "+third_party/blink/renderer/platform/bindings", "+third_party/blink/renderer/platform/cpu/mips/common_macros_msa.h", "+third_party/blink/renderer/platform/cross_thread_functional.h", "+third_party/blink/renderer/platform/drag_image.h", "+third_party/blink/renderer/platform/fonts", - "+third_party/blink/renderer/platform/graphics", + "+third_party/blink/renderer/platform/geometry", "+third_party/blink/renderer/platform/heap", "+third_party/blink/renderer/platform/histogram.h", "+third_party/blink/renderer/platform/image-decoders", "+third_party/blink/renderer/platform/image-encoders", "+third_party/blink/renderer/platform/instrumentation", - "+third_party/blink/renderer/platform/json/json_values.h", + "+third_party/blink/renderer/platform/json", "+third_party/blink/renderer/platform/length.h", "+third_party/blink/renderer/platform/mojo/mojo_helper.h", "+third_party/blink/renderer/platform/network/mime/mime_type_registry.h",
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc index e67ef2b..c5f07c6 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
@@ -218,8 +218,6 @@ viz::TransferableResource resource3; std::unique_ptr<viz::SingleReleaseCallback> release_callback3; - IntSize initial_size(kInitialWidth, kInitialHeight); - // Produce resources. EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); drawing_buffer_->ClearFramebuffers(GL_STENCIL_BUFFER_BIT); @@ -521,7 +519,6 @@ // Request a resource. An image should already be created. Everything works // as expected. EXPECT_CALL(*gl_, BindTexImage2DMock(_)).Times(1); - IntSize initial_size(kInitialWidth, kInitialHeight); EXPECT_FALSE(drawing_buffer_->MarkContentsChanged()); EXPECT_TRUE(drawing_buffer_->PrepareTransferableResource(nullptr, &resource1, &release_callback1));
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc index d74303c..2cf41c55f 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc +++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -6,7 +6,6 @@ #include <vector> -#include "base/task_runner.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "cc/paint/filter_operations.h"
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc index 5ad6fed..0eb72f7 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc +++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
@@ -6,10 +6,8 @@ #include <memory> #include "base/memory/ptr_util.h" -#include "base/task_runner_util.h" #include "base/test/scoped_task_environment.h" #include "base/test/simple_test_tick_clock.h" -#include "base/threading/thread.h" #include "cc/layers/video_frame_provider.h" #include "cc/test/layer_test_common.h" #include "cc/trees/layer_tree_settings.h"
diff --git a/third_party/blink/renderer/platform/heap/DEPS b/third_party/blink/renderer/platform/heap/DEPS index c5aa107..5409786d 100644 --- a/third_party/blink/renderer/platform/heap/DEPS +++ b/third_party/blink/renderer/platform/heap/DEPS
@@ -8,9 +8,7 @@ # Dependencies. "+base/atomicops.h", "+base/bits.h", - "+base/compiler_specific.h", "+base/synchronization/lock.h", - "+base/sys_info.h", "+third_party/blink/renderer/platform/bindings", "+third_party/blink/renderer/platform/cross_thread_functional.h",
diff --git a/third_party/blink/renderer/platform/image-encoders/DEPS b/third_party/blink/renderer/platform/image-encoders/DEPS index 5acbcd3..b78682ac 100644 --- a/third_party/blink/renderer/platform/image-encoders/DEPS +++ b/third_party/blink/renderer/platform/image-encoders/DEPS
@@ -6,13 +6,8 @@ "+third_party/blink/renderer/platform/image-encoders", # Dependencies. - "+third_party/blink/renderer/platform/geometry", - "+third_party/blink/renderer/platform/graphics", "+third_party/blink/renderer/platform/histogram.h", - "+third_party/blink/renderer/platform/instrumentation", "+third_party/blink/renderer/platform/network/mime/mime_type_registry.h", "+third_party/blink/renderer/platform/platform_export.h", - "+third_party/blink/renderer/platform/shared_buffer.h", - "+third_party/blink/renderer/platform/testing", "+third_party/blink/renderer/platform/wtf", ]
diff --git a/third_party/blink/renderer/platform/instrumentation/DEPS b/third_party/blink/renderer/platform/instrumentation/DEPS index 20dc455..7f6cc453 100644 --- a/third_party/blink/renderer/platform/instrumentation/DEPS +++ b/third_party/blink/renderer/platform/instrumentation/DEPS
@@ -8,10 +8,8 @@ # Dependencies. "+base/gtest_prod_util.h", "+base/json", - "+base/macros.h", "+base/memory", "+base/strings", - "+base/time", "+base/trace_event", "+base/values.h", "+skia/ext/skia_trace_memory_dump_impl.h",
diff --git a/third_party/blink/renderer/platform/layout_unit.h b/third_party/blink/renderer/platform/layout_unit.h index 7865a05..8521847d 100644 --- a/third_party/blink/renderer/platform/layout_unit.h +++ b/third_party/blink/renderer/platform/layout_unit.h
@@ -58,13 +58,13 @@ // TODO(thakis): Remove these two lines once http://llvm.org/PR26504 is resolved class PLATFORM_EXPORT LayoutUnit; -inline bool operator<(const LayoutUnit&, const LayoutUnit&); +constexpr inline bool operator<(const LayoutUnit&, const LayoutUnit&); class LayoutUnit { DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: - LayoutUnit() : value_(0) {} + constexpr LayoutUnit() : value_(0) {} explicit LayoutUnit(int value) { SetValue(value); } explicit LayoutUnit(unsigned short value) { SetValue(value); } explicit LayoutUnit(unsigned value) { SetValue(value); } @@ -107,11 +107,11 @@ return v; } - int ToInt() const { return value_ / kFixedPointDenominator; } - float ToFloat() const { + constexpr int ToInt() const { return value_ / kFixedPointDenominator; } + constexpr float ToFloat() const { return static_cast<float>(value_) / kFixedPointDenominator; } - double ToDouble() const { + constexpr double ToDouble() const { return static_cast<double>(value_) / kFixedPointDenominator; } unsigned ToUnsigned() const { @@ -126,16 +126,16 @@ operator int() const = delete; operator unsigned() const = delete; - operator double() const { return ToDouble(); } - operator float() const { return ToFloat(); } - operator bool() const { return value_; } + constexpr operator double() const { return ToDouble(); } + constexpr operator float() const { return ToFloat(); } + constexpr operator bool() const { return value_; } LayoutUnit operator++(int) { value_ = ClampAdd(value_, kFixedPointDenominator); return *this; } - inline int RawValue() const { return value_; } + constexpr int RawValue() const { return value_; } inline void SetRawValue(int value) { value_ = value; } void SetRawValue(long long value) { REPORT_OVERFLOW(value > std::numeric_limits<int>::min() && @@ -252,11 +252,11 @@ int value_; }; -inline bool operator<=(const LayoutUnit& a, const LayoutUnit& b) { +constexpr bool operator<=(const LayoutUnit& a, const LayoutUnit& b) { return a.RawValue() <= b.RawValue(); } -inline bool operator<=(const LayoutUnit& a, float b) { +constexpr bool operator<=(const LayoutUnit& a, float b) { return a.ToFloat() <= b; } @@ -264,7 +264,7 @@ return a <= LayoutUnit(b); } -inline bool operator<=(const float a, const LayoutUnit& b) { +constexpr bool operator<=(const float a, const LayoutUnit& b) { return a <= b.ToFloat(); } @@ -272,7 +272,7 @@ return LayoutUnit(a) <= b; } -inline bool operator>=(const LayoutUnit& a, const LayoutUnit& b) { +constexpr bool operator>=(const LayoutUnit& a, const LayoutUnit& b) { return a.RawValue() >= b.RawValue(); } @@ -280,11 +280,11 @@ return a >= LayoutUnit(b); } -inline bool operator>=(const float a, const LayoutUnit& b) { +constexpr bool operator>=(const float a, const LayoutUnit& b) { return a >= b.ToFloat(); } -inline bool operator>=(const LayoutUnit& a, float b) { +constexpr bool operator>=(const LayoutUnit& a, float b) { return a.ToFloat() >= b; } @@ -292,7 +292,7 @@ return LayoutUnit(a) >= b; } -inline bool operator<(const LayoutUnit& a, const LayoutUnit& b) { +constexpr bool operator<(const LayoutUnit& a, const LayoutUnit& b) { return a.RawValue() < b.RawValue(); } @@ -300,11 +300,11 @@ return a < LayoutUnit(b); } -inline bool operator<(const LayoutUnit& a, float b) { +constexpr bool operator<(const LayoutUnit& a, float b) { return a.ToFloat() < b; } -inline bool operator<(const LayoutUnit& a, double b) { +constexpr bool operator<(const LayoutUnit& a, double b) { return a.ToDouble() < b; } @@ -312,19 +312,19 @@ return LayoutUnit(a) < b; } -inline bool operator<(const float a, const LayoutUnit& b) { +constexpr bool operator<(const float a, const LayoutUnit& b) { return a < b.ToFloat(); } -inline bool operator>(const LayoutUnit& a, const LayoutUnit& b) { +constexpr bool operator>(const LayoutUnit& a, const LayoutUnit& b) { return a.RawValue() > b.RawValue(); } -inline bool operator>(const LayoutUnit& a, double b) { +constexpr bool operator>(const LayoutUnit& a, double b) { return a.ToDouble() > b; } -inline bool operator>(const LayoutUnit& a, float b) { +constexpr bool operator>(const LayoutUnit& a, float b) { return a.ToFloat() > b; } @@ -336,15 +336,15 @@ return LayoutUnit(a) > b; } -inline bool operator>(const float a, const LayoutUnit& b) { +constexpr bool operator>(const float a, const LayoutUnit& b) { return a > b.ToFloat(); } -inline bool operator>(const double a, const LayoutUnit& b) { +constexpr bool operator>(const double a, const LayoutUnit& b) { return a > b.ToDouble(); } -inline bool operator!=(const LayoutUnit& a, const LayoutUnit& b) { +constexpr bool operator!=(const LayoutUnit& a, const LayoutUnit& b) { return a.RawValue() != b.RawValue(); } @@ -360,7 +360,7 @@ return a != LayoutUnit(b); } -inline bool operator==(const LayoutUnit& a, const LayoutUnit& b) { +constexpr bool operator==(const LayoutUnit& a, const LayoutUnit& b) { return a.RawValue() == b.RawValue(); } @@ -372,11 +372,11 @@ return LayoutUnit(a) == b; } -inline bool operator==(const LayoutUnit& a, float b) { +constexpr bool operator==(const LayoutUnit& a, float b) { return a.ToFloat() == b; } -inline bool operator==(const float a, const LayoutUnit& b) { +constexpr bool operator==(const float a, const LayoutUnit& b) { return a == b.ToFloat(); } @@ -452,11 +452,11 @@ return LayoutUnit(a) * b; } -inline float operator*(const float a, const LayoutUnit& b) { +constexpr float operator*(const float a, const LayoutUnit& b) { return a * b.ToFloat(); } -inline double operator*(const double a, const LayoutUnit& b) { +constexpr double operator*(const double a, const LayoutUnit& b) { return a * b.ToDouble(); } @@ -468,11 +468,11 @@ return return_val; } -inline float operator/(const LayoutUnit& a, float b) { +constexpr float operator/(const LayoutUnit& a, float b) { return a.ToFloat() / b; } -inline double operator/(const LayoutUnit& a, double b) { +constexpr double operator/(const LayoutUnit& a, double b) { return a.ToDouble() / b; } @@ -496,11 +496,11 @@ return a / LayoutUnit(b); } -inline float operator/(const float a, const LayoutUnit& b) { +constexpr float operator/(const float a, const LayoutUnit& b) { return a / b.ToFloat(); } -inline double operator/(const double a, const LayoutUnit& b) { +constexpr double operator/(const double a, const LayoutUnit& b) { return a / b.ToDouble(); } @@ -546,11 +546,11 @@ return LayoutUnit(a) + b; } -inline float operator+(const float a, const LayoutUnit& b) { +constexpr inline float operator+(const float a, const LayoutUnit& b) { return a + b.ToFloat(); } -inline double operator+(const double a, const LayoutUnit& b) { +constexpr inline double operator+(const double a, const LayoutUnit& b) { return a + b.ToDouble(); } @@ -568,11 +568,11 @@ return a - LayoutUnit(b); } -inline float operator-(const LayoutUnit& a, float b) { +constexpr float operator-(const LayoutUnit& a, float b) { return a.ToFloat() - b; } -inline double operator-(const LayoutUnit& a, double b) { +constexpr double operator-(const LayoutUnit& a, double b) { return a.ToDouble() - b; } @@ -580,7 +580,7 @@ return LayoutUnit(a) - b; } -inline float operator-(const float a, const LayoutUnit& b) { +constexpr float operator-(const float a, const LayoutUnit& b) { return a - b.ToFloat(); }
diff --git a/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc b/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc index 2280203..d43122fc6 100644 --- a/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc +++ b/third_party/blink/renderer/platform/loader/fetch/raw_resource.cc
@@ -205,7 +205,7 @@ if (response.WasFallbackRequiredByServiceWorker()) { // The ServiceWorker asked us to re-fetch the request. This resource must // not be reused. - // Note: This logic is needed here because DocumentThreadableLoader handles + // Note: This logic is needed here because ThreadableLoader handles // CORS independently from ResourceLoader. Fix it. if (IsMainThread()) GetMemoryCache()->Remove(this);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.cc b/third_party/blink/renderer/platform/loader/fetch/resource.cc index 97a1597..83a2c12e 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -873,19 +873,19 @@ case network::mojom::FetchRequestMode::kCORS: case network::mojom::FetchRequestMode::kSameOrigin: case network::mojom::FetchRequestMode::kCORSWithForcedPreflight: - // We have two separate CORS handling logics in DocumentThreadableLoader + // We have two separate CORS handling logics in ThreadableLoader // and ResourceLoader and sharing resources is difficult when they are // handled differently. if (options_.cors_handling_by_resource_fetcher != new_options.cors_handling_by_resource_fetcher) { - // If the existing one is handled in DocumentThreadableLoader and the + // If the existing one is handled in ThreadableLoader and the // new one is handled in ResourceLoader, reusing the existing one will // lead to CORS violations. if (!options_.cors_handling_by_resource_fetcher) return false; // Otherwise (i.e., if the existing one is handled in ResourceLoader - // and the new one is handled in DocumentThreadableLoader), reusing + // and the new one is handled in ThreadableLoader), reusing // the existing one will lead to double check which is harmless. } break;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index a3a04d9..5ab5d282 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -654,7 +654,7 @@ : SecurityViolationReportingPolicy::kReport; // Note that resource_request.GetRedirectStatus() may return kFollowedRedirect - // here since e.g. DocumentThreadableLoader may create a new Resource from + // here since e.g. ThreadableLoader may create a new Resource from // a ResourceRequest that originates from the ResourceRequest passed to // the redirect handling callback.
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h b/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h index 0907407..3617906 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h
@@ -59,7 +59,7 @@ kRequestAsynchronously }; -// Used by the DocumentThreadableLoader to turn off part of the CORS handling +// Used by the ThreadableLoader to turn off part of the CORS handling // logic in the ResourceFetcher to use its own CORS handling logic. enum CORSHandlingByResourceFetcher { kDisableCORSHandlingByResourceFetcher, @@ -102,7 +102,7 @@ // When set to kDisableCORSHandlingByResourceFetcher, the ResourceFetcher // suppresses part of its CORS handling logic. - // Used by DocumentThreadableLoader which does CORS handling by itself. + // Used by ThreadableLoader which does CORS handling by itself. CORSHandlingByResourceFetcher cors_handling_by_resource_fetcher; // Corresponds to the CORS flag in the Fetch spec.
diff --git a/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto b/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto index d39f2bb8..a3a67b1c 100644 --- a/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto +++ b/third_party/blink/renderer/platform/scheduler/base/proto/sequence_manager_test_description.proto
@@ -21,7 +21,7 @@ } message Action { - // NEXT ID = 9 + // NEXT ID = 11 optional uint64 action_id = 1; @@ -33,6 +33,8 @@ ShutdownTaskQueueAction shutdown_task_queue = 6; CancelTaskAction cancel_task = 7; CreateQueueVoterAction create_queue_voter = 8; + InsertFenceAction insert_fence = 9; + RemoveFenceAction remove_fence = 10; } } @@ -42,7 +44,7 @@ // Only needed for testing the fuzzer processor. optional uint64 task_id = 1; - optional uint64 duration_ms = 2; + optional uint32 duration_ms = 2; // If not set, then this is a no-op task. repeated Action actions = 3; @@ -66,7 +68,7 @@ optional Task task = 2; // Delay parameter passed to TaskQueue::PostDelayedTask. - optional uint64 delay_ms = 3; + optional uint32 delay_ms = 3; } // Describes the grammar of TaskQueue::SetQueuePriority. @@ -121,5 +123,27 @@ optional uint64 task_id = 1; } + message InsertFenceAction { + // NEXT ID = 3 + enum FencePosition { + NOW = 0; + BEGINNING_OF_TIME = 1; + } + + optional FencePosition position = 1 [default = NOW]; + + // Used to identify the |task_queue_id|'s oldest available queue to + // insert the fence to (modulo the number of available queues). + optional uint64 task_queue_id = 2; + } + + message RemoveFenceAction { + // NEXT ID = 2 + + // Used to identify the |task_queue_id|'s oldest available queue to remove a + // fence from, if one exists (modulo the number of available queues). + optional uint64 task_queue_id = 2; + } + repeated Action initial_actions = 1; }
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc index 73e7ff74..484bc1de 100644 --- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc +++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.cc
@@ -89,6 +89,10 @@ action.shutdown_task_queue()); } else if (action.has_cancel_task()) { ExecuteCancelTaskAction(action.action_id(), action.cancel_task()); + } else if (action.has_insert_fence()) { + ExecuteInsertFenceAction(action.action_id(), action.insert_fence()); + } else if (action.has_remove_fence()) { + ExecuteRemoveFenceAction(action.action_id(), action.remove_fence()); } else { ExecutePostDelayedTaskAction(action.action_id(), action.post_delayed_task()); @@ -202,17 +206,45 @@ test_task_runner_->GetMockTickClock()->NowTicks()); if (!pending_tasks_.empty()) { - size_t queue_index = action.task_id() % pending_tasks_.size(); - pending_tasks_[queue_index]->weak_ptr_factory_.InvalidateWeakPtrs(); + size_t task_index = action.task_id() % pending_tasks_.size(); + pending_tasks_[task_index]->weak_ptr_factory_.InvalidateWeakPtrs(); // If it is already running, it is a parent task and will be deleted when // it is done. - if (!pending_tasks_[queue_index]->is_running) { - pending_tasks_.erase(pending_tasks_.begin() + queue_index); + if (!pending_tasks_[task_index]->is_running) { + pending_tasks_.erase(pending_tasks_.begin() + task_index); } } } +void SequenceManagerFuzzerProcessor::ExecuteInsertFenceAction( + uint64_t action_id, + const SequenceManagerTestDescription::InsertFenceAction& action) { + LogActionForTesting(action_id, ActionForTest::ActionType::kInsertFence, + test_task_runner_->GetMockTickClock()->NowTicks()); + + size_t queue_index = action.task_queue_id() % task_queues_.size(); + + if (action.position() == + SequenceManagerTestDescription::InsertFenceAction::NOW) { + task_queues_[queue_index].queue.get()->InsertFence( + TaskQueue::InsertFencePosition::kNow); + } else { + task_queues_[queue_index].queue.get()->InsertFence( + TaskQueue::InsertFencePosition::kBeginningOfTime); + } +} + +void SequenceManagerFuzzerProcessor::ExecuteRemoveFenceAction( + uint64_t action_id, + const SequenceManagerTestDescription::RemoveFenceAction& action) { + LogActionForTesting(action_id, ActionForTest::ActionType::kRemoveFence, + test_task_runner_->GetMockTickClock()->NowTicks()); + + size_t queue_index = action.task_queue_id() % task_queues_.size(); + task_queues_[queue_index].queue.get()->RemoveFence(); +} + void SequenceManagerFuzzerProcessor::ExecuteTask( const SequenceManagerTestDescription::Task& task) { TimeTicks start_time = test_task_runner_->GetMockTickClock()->NowTicks();
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h index fcd2502..a98d7d78 100644 --- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h +++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor.h
@@ -47,6 +47,8 @@ kCreateQueueVoter, kCancelTask, kShutdownTaskQueue, + kInsertFence, + kRemoveFence }; ActionForTest(uint64_t id, ActionType type, uint64_t start); @@ -110,6 +112,12 @@ void ExecuteCancelTaskAction( uint64_t action_id, const SequenceManagerTestDescription::CancelTaskAction& action); + void ExecuteInsertFenceAction( + uint64_t action_id, + const SequenceManagerTestDescription::InsertFenceAction& action); + void ExecuteRemoveFenceAction( + uint64_t action_id, + const SequenceManagerTestDescription::RemoveFenceAction& action); void ExecuteTask(const SequenceManagerTestDescription::Task& task);
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc index aba61e4..a5384d6 100644 --- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_fuzzer_processor_unittest.cc
@@ -944,5 +944,125 @@ EXPECT_THAT(executed_actions, ContainerEq(expected_actions)); } +TEST(SequenceManagerFuzzerProcessorTest, InsertAndRemoveFence) { + std::vector<ActionForTest> executed_actions; + std::vector<TaskForTest> executed_tasks; + + // Describes a test that inserts a fence to a task queue after a delay of + // 20ms, posts a task to it after a delay of 25ms, and removes the fence after + // a delay of 30ms. + SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"( + initial_actions { + action_id : 1 + create_task_queue{ + } + } + initial_actions { + action_id : 2 + post_delayed_task { + delay_ms : 20 + task_queue_id : 2 + task { + task_id : 1 + actions { + action_id : 3 + insert_fence { + position: NOW + task_queue_id: 1 + } + } + } + } + } + initial_actions { + action_id : 4 + post_delayed_task { + delay_ms : 30 + task_queue_id : 2 + task { + task_id : 2 + actions { + action_id : 5 + remove_fence { + task_queue_id: 1 + } + } + } + } + } + initial_actions { + action_id: 6 + post_delayed_task { + delay_ms: 25 + task_queue_id: 1 + task { + task_id: 3 + } + } + })", + &executed_tasks, + &executed_actions); + + std::vector<ActionForTest> expected_actions; + expected_actions.emplace_back(1, ActionForTest::ActionType::kCreateTaskQueue, + 0); + expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask, + 0); + expected_actions.emplace_back(4, ActionForTest::ActionType::kPostDelayedTask, + 0); + expected_actions.emplace_back(6, ActionForTest::ActionType::kPostDelayedTask, + 0); + expected_actions.emplace_back(3, ActionForTest::ActionType::kInsertFence, 20); + expected_actions.emplace_back(5, ActionForTest::ActionType::kRemoveFence, 30); + + EXPECT_THAT(executed_actions, ContainerEq(expected_actions)); + + std::vector<TaskForTest> expected_tasks; + expected_tasks.emplace_back(1, 20, 20); + expected_tasks.emplace_back(2, 30, 30); + + // Task with id 3 will not execute until the fence is removed from the task + // queue it was posted to. + expected_tasks.emplace_back(3, 30, 30); + + EXPECT_THAT(executed_tasks, ContainerEq(expected_tasks)); +} + +TEST(SequenceManagerFuzzerProcessorTest, ThrottleTaskQueue) { + std::vector<ActionForTest> executed_actions; + std::vector<TaskForTest> executed_tasks; + + // Describes a test that throttles a task queue, and posts a task to it. + SequenceManagerFuzzerProcessorForTest::ParseAndRun(R"( + initial_actions { + action_id : 1 + insert_fence { + position: BEGINNING_OF_TIME + task_queue_id: 1 + } + } + initial_actions { + action_id: 2 + post_delayed_task { + task_queue_id: 1 + task { + task_id: 3 + } + } + })", + &executed_tasks, + &executed_actions); + + std::vector<ActionForTest> expected_actions; + expected_actions.emplace_back(1, ActionForTest::ActionType::kInsertFence, 0); + expected_actions.emplace_back(2, ActionForTest::ActionType::kPostDelayedTask, + 0); + + EXPECT_THAT(executed_actions, ContainerEq(expected_actions)); + + // Task queue with id 1 is throttled, so posted tasks will not get executed. + EXPECT_THAT(executed_tasks, IsEmpty()); +} + } // namespace sequence_manager } // namespace base
diff --git a/third_party/blink/renderer/platform/scroll/scroll_animator.cc b/third_party/blink/renderer/platform/scroll/scroll_animator.cc index 565abbe..d53a19e 100644 --- a/third_party/blink/renderer/platform/scroll/scroll_animator.cc +++ b/third_party/blink/renderer/platform/scroll/scroll_animator.cc
@@ -169,7 +169,7 @@ // of sending to the compositor. if (run_state_ == RunState::kRunningOnMainThread) { animation_curve_->UpdateTarget( - time_function_() - start_time_, + TimeDelta::FromSecondsD(time_function_() - start_time_), CompositorOffsetFromBlinkOffset(target_offset)); return true; } @@ -329,7 +329,7 @@ // ::adjustScrollOffsetAnimation should have made the necessary // adjustment to the curve. animation_curve_->UpdateTarget( - time_function_() - start_time_, + TimeDelta::FromSecondsD(time_function_() - start_time_), CompositorOffsetFromBlinkOffset(target_offset_)); }
diff --git a/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc b/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc index 531d274..5cc3d0c 100644 --- a/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc +++ b/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc
@@ -33,7 +33,6 @@ return this; // convert the TransformOperations into matrices - FloatSize size; TransformationMatrix from_t; TransformationMatrix to_t(a_, b_, c_, d_, e_, f_); if (from) {
diff --git a/third_party/blink/renderer/platform/wtf/math_extras.h b/third_party/blink/renderer/platform/wtf/math_extras.h index c090e11..6913d3dc 100644 --- a/third_party/blink/renderer/platform/wtf/math_extras.h +++ b/third_party/blink/renderer/platform/wtf/math_extras.h
@@ -48,83 +48,83 @@ #include <sys/types.h> #endif -const double kPiDouble = M_PI; -const float kPiFloat = static_cast<float>(M_PI); +constexpr double kPiDouble = M_PI; +constexpr float kPiFloat = static_cast<float>(M_PI); -const double kPiOverTwoDouble = M_PI_2; -const float kPiOverTwoFloat = static_cast<float>(M_PI_2); +constexpr double kPiOverTwoDouble = M_PI_2; +constexpr float kPiOverTwoFloat = static_cast<float>(M_PI_2); -const double kPiOverFourDouble = M_PI_4; -const float kPiOverFourFloat = static_cast<float>(M_PI_4); +constexpr double kPiOverFourDouble = M_PI_4; +constexpr float kPiOverFourFloat = static_cast<float>(M_PI_4); -const double kTwoPiDouble = kPiDouble * 2.0; -const float kTwoPiFloat = kPiFloat * 2.0f; +constexpr double kTwoPiDouble = kPiDouble * 2.0; +constexpr float kTwoPiFloat = kPiFloat * 2.0f; -inline double deg2rad(double d) { +constexpr double deg2rad(double d) { return d * kPiDouble / 180.0; } -inline double rad2deg(double r) { +constexpr double rad2deg(double r) { return r * 180.0 / kPiDouble; } -inline double deg2grad(double d) { +constexpr double deg2grad(double d) { return d * 400.0 / 360.0; } -inline double grad2deg(double g) { +constexpr double grad2deg(double g) { return g * 360.0 / 400.0; } -inline double turn2deg(double t) { +constexpr double turn2deg(double t) { return t * 360.0; } -inline double deg2turn(double d) { +constexpr double deg2turn(double d) { return d / 360.0; } -inline double rad2grad(double r) { +constexpr double rad2grad(double r) { return r * 200.0 / kPiDouble; } -inline double grad2rad(double g) { +constexpr double grad2rad(double g) { return g * kPiDouble / 200.0; } -inline double turn2grad(double t) { +constexpr double turn2grad(double t) { return t * 400; } -inline double grad2turn(double g) { +constexpr double grad2turn(double g) { return g / 400; } -inline double rad2turn(double r) { +constexpr double rad2turn(double r) { return r / kTwoPiDouble; } -inline double turn2rad(double t) { +constexpr double turn2rad(double t) { return t * kTwoPiDouble; } -inline float deg2rad(float d) { +constexpr float deg2rad(float d) { return d * kPiFloat / 180.0f; } -inline float rad2deg(float r) { +constexpr float rad2deg(float r) { return r * 180.0f / kPiFloat; } -inline float deg2grad(float d) { +constexpr float deg2grad(float d) { return d * 400.0f / 360.0f; } -inline float grad2deg(float g) { +constexpr float grad2deg(float g) { return g * 360.0f / 400.0f; } -inline float turn2deg(float t) { +constexpr float turn2deg(float t) { return t * 360.0f; } -inline float deg2turn(float d) { +constexpr float deg2turn(float d) { return d / 360.0f; } -inline float rad2grad(float r) { +constexpr float rad2grad(float r) { return r * 200.0f / kPiFloat; } -inline float grad2rad(float g) { +constexpr float grad2rad(float g) { return g * kPiFloat / 200.0f; } -inline float turn2grad(float t) { +constexpr float turn2grad(float t) { return t * 400; } -inline float grad2turn(float g) { +constexpr float grad2turn(float g) { return g / 400; } @@ -297,20 +297,20 @@ }; template <typename T> -inline T defaultMaximumForClamp() { +constexpr T defaultMaximumForClamp() { return std::numeric_limits<T>::max(); } // This basically reimplements C++11's std::numeric_limits<T>::lowest(). template <typename T> -inline T defaultMinimumForClamp() { +constexpr T defaultMinimumForClamp() { return std::numeric_limits<T>::min(); } template <> -inline float defaultMinimumForClamp<float>() { +constexpr float defaultMinimumForClamp<float>() { return -std::numeric_limits<float>::max(); } template <> -inline double defaultMinimumForClamp<double>() { +constexpr double defaultMinimumForClamp<double>() { return -std::numeric_limits<double>::max(); } @@ -324,16 +324,16 @@ return ClampToHelper<LimitType, ValueType>::clampTo(value, min, max); } -inline bool isWithinIntRange(float x) { +constexpr bool isWithinIntRange(float x) { return x > static_cast<float>(std::numeric_limits<int>::min()) && x < static_cast<float>(std::numeric_limits<int>::max()); } -static size_t greatestCommonDivisor(size_t a, size_t b) { +static constexpr size_t greatestCommonDivisor(size_t a, size_t b) { return b ? greatestCommonDivisor(b, a % b) : a; } -inline size_t lowestCommonMultiple(size_t a, size_t b) { +constexpr size_t lowestCommonMultiple(size_t a, size_t b) { return a && b ? a / greatestCommonDivisor(a, b) * b : 0; }
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium index aed01e02..73d39da 100644 --- a/third_party/crashpad/README.chromium +++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@ Short Name: crashpad URL: https://crashpad.chromium.org/ Version: unknown -Revision: fb0f7ca8d7eb55ca51b77eb89813a3283a461b0c +Revision: 2f3a8b8f72dccc7c1738eb496e46e86ee60ec4ed License: Apache 2.0 License File: crashpad/LICENSE Security Critical: yes
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS index dbdc3a4..34f1ef68 100644 --- a/third_party/crashpad/crashpad/DEPS +++ b/third_party/crashpad/crashpad/DEPS
@@ -37,6 +37,90 @@ 'crashpad/third_party/zlib/zlib': Var('chromium_git') + '/chromium/src/third_party/zlib@' + '13dc246a58e4b72104d35f9b1809af95221ebda7', + + # CIPD packages below. + 'crashpad/third_party/linux/clang/linux-amd64': { + 'packages': [ + { + 'package': 'fuchsia/clang/linux-amd64', + 'version': 'goma', + }, + ], + 'condition': 'checkout_linux and pull_linux_clang', + 'dep_type': 'cipd' + }, + 'crashpad/third_party/linux/clang/mac-amd64': { + 'packages': [ + { + 'package': 'fuchsia/clang/mac-amd64', + 'version': 'goma', + }, + ], + 'condition': 'checkout_fuchsia and host_os == "mac"', + 'dep_type': 'cipd' + }, + 'crashpad/third_party/fuchsia/clang/linux-amd64': { + 'packages': [ + { + 'package': 'fuchsia/clang/linux-amd64', + 'version': 'goma', + }, + ], + 'condition': 'checkout_fuchsia and host_os == "linux"', + 'dep_type': 'cipd' + }, + 'crashpad/third_party/fuchsia/qemu/mac-amd64': { + 'packages': [ + { + 'package': 'fuchsia/qemu/mac-amd64', + 'version': 'latest' + }, + ], + 'condition': 'checkout_fuchsia and host_os == "mac"', + 'dep_type': 'cipd' + }, + 'crashpad/third_party/fuchsia/qemu/linux-amd64': { + 'packages': [ + { + 'package': 'fuchsia/qemu/linux-amd64', + 'version': 'latest' + }, + ], + 'condition': 'checkout_fuchsia and host_os == "linux"', + 'dep_type': 'cipd' + }, + 'crashpad/third_party/fuchsia/sdk/linux-amd64': { + # The SDK is keyed to the host system because it contains build tools. + # Currently, linux-amd64 is the only SDK published (see + # https://chrome-infra-packages.appspot.com/#/?path=fuchsia/sdk). + # As long as this is the case, use that SDK package + # even on other build hosts. + # The sysroot (containing headers and libraries) and other components are + # related to the target and should be functional with an appropriate + # toolchain that runs on the build host (fuchsia_clang, above). + 'packages': [ + { + 'package': 'fuchsia/sdk/linux-amd64', + 'version': 'latest' + }, + ], + 'condition': 'checkout_fuchsia', + 'dep_type': 'cipd' + }, + 'crashpad/third_party/win/toolchain': { + # This package is only updated when the solution in .gclient includes an + # entry like: + # "custom_vars": { "pull_win_toolchain": True } + # This is because the contained bits are not redistributable. + 'packages': [ + { + 'package': 'chrome_internal/third_party/sdk/windows', + 'version': 'uploaded:2018-06-13' + }, + ], + 'condition': 'checkout_win and pull_win_toolchain', + 'dep_type': 'cipd' + }, } hooks = [ @@ -119,28 +203,6 @@ ], }, { - # This uses “cipd install” so that mac-amd64 and linux-amd64 can coexist - # peacefully. “cipd ensure” would remove the macOS package when running on a - # Linux build host and vice-versa. https://crbug.com/789364. This package is - # only updated when the solution in .gclient includes an entry like: - # "custom_vars": { "pull_linux_clang": True } - # The ref used is "goma". This is like "latest", but is considered a more - # stable latest by the Fuchsia toolchain team. - 'name': 'clang_linux', - 'pattern': '.', - 'condition': 'checkout_linux and pull_linux_clang', - 'action': [ - 'cipd', - 'install', - # sic, using Fuchsia team's generic build of clang for linux-amd64 to - # build for linux-amd64 target too. - 'fuchsia/clang/linux-amd64', - 'goma', - '-root', 'crashpad/third_party/linux/clang/linux-amd64', - '-log-level', 'info', - ], - }, - { # If using a local clang ("pull_linux_clang" above), also pull down a # sysroot. 'name': 'sysroot_linux', @@ -151,105 +213,6 @@ ], }, { - # Same rationale for using "install" rather than "ensure" as for first clang - # package. https://crbug.com/789364. - # Same rationale for using "goma" instead of "latest" as clang_linux above. - 'name': 'fuchsia_clang_mac', - 'pattern': '.', - 'condition': 'checkout_fuchsia and host_os == "mac"', - 'action': [ - 'cipd', - 'install', - 'fuchsia/clang/mac-amd64', - 'goma', - '-root', 'crashpad/third_party/fuchsia/clang/mac-amd64', - '-log-level', 'info', - ], - }, - { - # Same rationale for using "install" rather than "ensure" as for first clang - # package. https://crbug.com/789364. - # Same rationale for using "goma" instead of "latest" as clang_linux above. - 'name': 'fuchsia_clang_linux', - 'pattern': '.', - 'condition': 'checkout_fuchsia and host_os == "linux"', - 'action': [ - 'cipd', - 'install', - 'fuchsia/clang/linux-amd64', - 'goma', - '-root', 'crashpad/third_party/fuchsia/clang/linux-amd64', - '-log-level', 'info', - ], - }, - { - # Same rationale for using "install" rather than "ensure" as for clang - # packages. https://crbug.com/789364. - 'name': 'fuchsia_qemu_mac', - 'pattern': '.', - 'condition': 'checkout_fuchsia and host_os == "mac"', - 'action': [ - 'cipd', - 'install', - 'fuchsia/qemu/mac-amd64', - 'latest', - '-root', 'crashpad/third_party/fuchsia/qemu/mac-amd64', - '-log-level', 'info', - ], - }, - { - # Same rationale for using "install" rather than "ensure" as for clang - # packages. https://crbug.com/789364. - 'name': 'fuchsia_qemu_linux', - 'pattern': '.', - 'condition': 'checkout_fuchsia and host_os == "linux"', - 'action': [ - 'cipd', - 'install', - 'fuchsia/qemu/linux-amd64', - 'latest', - '-root', 'crashpad/third_party/fuchsia/qemu/linux-amd64', - '-log-level', 'info', - ], - }, - { - # The SDK is keyed to the host system because it contains build tools. - # Currently, linux-amd64 is the only SDK published (see - # https://chrome-infra-packages.appspot.com/#/?path=fuchsia/sdk). As long as - # this is the case, use that SDK package even on other build hosts. The - # sysroot (containing headers and libraries) and other components are - # related to the target and should be functional with an appropriate - # toolchain that runs on the build host (fuchsia_clang, above). - 'name': 'fuchsia_sdk', - 'pattern': '.', - 'condition': 'checkout_fuchsia', - 'action': [ - 'cipd', - 'install', - 'fuchsia/sdk/linux-amd64', - 'latest', - '-root', 'crashpad/third_party/fuchsia/sdk/linux-amd64', - '-log-level', 'info', - ], - }, - { - 'name': 'toolchain_win', - 'pattern': '.', - # This package is only updated when the solution in .gclient includes an - # entry like: - # "custom_vars": { "pull_win_toolchain": True } - # This is because the contained bits are not redistributable. - 'condition': 'checkout_win and pull_win_toolchain', - 'action': [ - 'cipd', - 'install', - 'chrome_internal/third_party/sdk/windows', - 'uploaded:2018-06-13', - '-root', 'crashpad/third_party/win/toolchain', - '-log-level', 'info', - ], - }, - { 'name': 'gyp', 'pattern': '\.gypi?$', 'action': ['python', 'crashpad/build/gyp_crashpad.py'],
diff --git a/third_party/crashpad/crashpad/client/client_argv_handling.cc b/third_party/crashpad/crashpad/client/client_argv_handling.cc index 9b813b1..6933aac 100644 --- a/third_party/crashpad/crashpad/client/client_argv_handling.cc +++ b/third_party/crashpad/crashpad/client/client_argv_handling.cc
@@ -27,38 +27,38 @@ } // namespace -void BuildHandlerArgvStrings( +std::vector<std::string> BuildHandlerArgvStrings( const base::FilePath& handler, const base::FilePath& database, const base::FilePath& metrics_dir, const std::string& url, const std::map<std::string, std::string>& annotations, - const std::vector<std::string>& arguments, - std::vector<std::string>* argv_strings) { - argv_strings->clear(); + const std::vector<std::string>& arguments) { + std::vector<std::string> argv_strings(1, handler.value()); - argv_strings->push_back(handler.value()); for (const auto& argument : arguments) { - argv_strings->push_back(argument); + argv_strings.push_back(argument); } if (!database.empty()) { - argv_strings->push_back(FormatArgumentString("database", database.value())); + argv_strings.push_back(FormatArgumentString("database", database.value())); } if (!metrics_dir.empty()) { - argv_strings->push_back( + argv_strings.push_back( FormatArgumentString("metrics-dir", metrics_dir.value())); } if (!url.empty()) { - argv_strings->push_back(FormatArgumentString("url", url)); + argv_strings.push_back(FormatArgumentString("url", url)); } for (const auto& kv : annotations) { - argv_strings->push_back( + argv_strings.push_back( FormatArgumentString("annotation", kv.first + '=' + kv.second)); } + + return argv_strings; } void ConvertArgvStrings(const std::vector<std::string>& argv_strings,
diff --git a/third_party/crashpad/crashpad/client/client_argv_handling.h b/third_party/crashpad/crashpad/client/client_argv_handling.h index 0ef3a15..d380b1a 100644 --- a/third_party/crashpad/crashpad/client/client_argv_handling.h +++ b/third_party/crashpad/crashpad/client/client_argv_handling.h
@@ -28,16 +28,14 @@ //! //! See StartHandlerAtCrash() for documentation on the input arguments. //! -//! \param[out] A argv_strings vector of arguments suitable for starting the -//! handler with. -void BuildHandlerArgvStrings( +//! \return A vector of arguments suitable for starting the handler with. +std::vector<std::string> BuildHandlerArgvStrings( const base::FilePath& handler, const base::FilePath& database, const base::FilePath& metrics_dir, const std::string& url, const std::map<std::string, std::string>& annotations, - const std::vector<std::string>& arguments, - std::vector<std::string>* argv_strings); + const std::vector<std::string>& arguments); //! \brief Flattens a string vector into a const char* vector suitable for use //! in an exec() call.
diff --git a/third_party/crashpad/crashpad/client/crash_report_database.cc b/third_party/crashpad/crashpad/client/crash_report_database.cc index aa365be..d300a8f9 100644 --- a/third_party/crashpad/crashpad/client/crash_report_database.cc +++ b/third_party/crashpad/crashpad/client/crash_report_database.cc
@@ -69,7 +69,8 @@ reader_(std::make_unique<FileReader>()), database_(nullptr), attachment_readers_(), - attachment_map_() {} + attachment_map_(), + report_metrics_(false) {} CrashReportDatabase::UploadReport::~UploadReport() { if (database_) {
diff --git a/third_party/crashpad/crashpad/client/crash_report_database.h b/third_party/crashpad/crashpad/client/crash_report_database.h index 9ceeddc33..d115c74b 100644 --- a/third_party/crashpad/crashpad/client/crash_report_database.h +++ b/third_party/crashpad/crashpad/client/crash_report_database.h
@@ -178,6 +178,7 @@ CrashReportDatabase* database_; std::vector<std::unique_ptr<FileReader>> attachment_readers_; std::map<std::string, FileReader*> attachment_map_; + bool report_metrics_; DISALLOW_COPY_AND_ASSIGN(UploadReport); }; @@ -326,11 +327,16 @@ //! \param[in] uuid The unique identifier for the crash report record. //! \param[out] report A crash report record for the report to be uploaded. //! Only valid if this returns #kNoError. + //! \param[in] report_metrics If `false`, metrics will not be recorded for + //! this upload attempt when RecordUploadComplete() is called or \a report + //! is destroyed. Metadata for the upload attempt will still be recorded + //! in the database. //! //! \return The operation status code. virtual OperationStatus GetReportForUploading( const UUID& uuid, - std::unique_ptr<const UploadReport>* report) = 0; + std::unique_ptr<const UploadReport>* report, + bool report_metrics = true) = 0; //! \brief Records a successful upload for a report and updates the last //! upload attempt time as returned by
diff --git a/third_party/crashpad/crashpad/client/crash_report_database_generic.cc b/third_party/crashpad/crashpad/client/crash_report_database_generic.cc index 6dc8e9e..8e93237 100644 --- a/third_party/crashpad/crashpad/client/crash_report_database_generic.cc +++ b/third_party/crashpad/crashpad/client/crash_report_database_generic.cc
@@ -180,7 +180,8 @@ OperationStatus GetCompletedReports(std::vector<Report>* reports) override; OperationStatus GetReportForUploading( const UUID& uuid, - std::unique_ptr<const UploadReport>* report) override; + std::unique_ptr<const UploadReport>* report, + bool report_metrics) override; OperationStatus SkipReportUpload(const UUID& uuid, Metrics::CrashSkippedReason reason) override; OperationStatus DeleteReport(const UUID& uuid) override; @@ -455,7 +456,8 @@ OperationStatus CrashReportDatabaseGeneric::GetReportForUploading( const UUID& uuid, - std::unique_ptr<const UploadReport>* report) { + std::unique_ptr<const UploadReport>* report, + bool report_metrics) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); auto upload_report = std::make_unique<LockfileUploadReport>(); @@ -470,6 +472,7 @@ if (!upload_report->Initialize(path, this)) { return kFileSystemError; } + upload_report->report_metrics_ = report_metrics; report->reset(upload_report.release()); return kNoError; @@ -609,7 +612,9 @@ const std::string& id) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - Metrics::CrashUploadAttempted(successful); + if (report->report_metrics_) { + Metrics::CrashUploadAttempted(successful); + } time_t now = time(nullptr); report->id = id;
diff --git a/third_party/crashpad/crashpad/client/crash_report_database_mac.mm b/third_party/crashpad/crashpad/client/crash_report_database_mac.mm index 79b876d..3106dc2c 100644 --- a/third_party/crashpad/crashpad/client/crash_report_database_mac.mm +++ b/third_party/crashpad/crashpad/client/crash_report_database_mac.mm
@@ -141,7 +141,8 @@ OperationStatus GetCompletedReports(std::vector<Report>* reports) override; OperationStatus GetReportForUploading( const UUID& uuid, - std::unique_ptr<const UploadReport>* report) override; + std::unique_ptr<const UploadReport>* report, + bool report_metrics) override; OperationStatus SkipReportUpload(const UUID& uuid, Metrics::CrashSkippedReason reason) override; OperationStatus DeleteReport(const UUID& uuid) override; @@ -422,7 +423,8 @@ CrashReportDatabase::OperationStatus CrashReportDatabaseMac::GetReportForUploading( const UUID& uuid, - std::unique_ptr<const UploadReport>* report) { + std::unique_ptr<const UploadReport>* report, + bool report_metrics) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); auto upload_report = std::make_unique<UploadReportMac>(); @@ -444,6 +446,7 @@ upload_report->database_ = this; upload_report->lock_fd.reset(lock.release()); + upload_report->report_metrics_ = report_metrics; report->reset(upload_report.release()); return kNoError; } @@ -454,7 +457,9 @@ const std::string& id) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - Metrics::CrashUploadAttempted(successful); + if (report->report_metrics_) { + Metrics::CrashUploadAttempted(successful); + } DCHECK(report); DCHECK(successful || id.empty());
diff --git a/third_party/crashpad/crashpad/client/crash_report_database_win.cc b/third_party/crashpad/crashpad/client/crash_report_database_win.cc index e19e605..8967770 100644 --- a/third_party/crashpad/crashpad/client/crash_report_database_win.cc +++ b/third_party/crashpad/crashpad/client/crash_report_database_win.cc
@@ -594,7 +594,8 @@ OperationStatus GetCompletedReports(std::vector<Report>* reports) override; OperationStatus GetReportForUploading( const UUID& uuid, - std::unique_ptr<const UploadReport>* report) override; + std::unique_ptr<const UploadReport>* report, + bool report_metrics) override; OperationStatus SkipReportUpload(const UUID& uuid, Metrics::CrashSkippedReason reason) override; OperationStatus DeleteReport(const UUID& uuid) override; @@ -731,7 +732,8 @@ OperationStatus CrashReportDatabaseWin::GetReportForUploading( const UUID& uuid, - std::unique_ptr<const UploadReport>* report) { + std::unique_ptr<const UploadReport>* report, + bool report_metrics) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); std::unique_ptr<Metadata> metadata(AcquireMetadata()); @@ -749,6 +751,7 @@ if (!upload_report->Initialize(upload_report->file_path, this)) { return kFileSystemError; } + upload_report->report_metrics_ = report_metrics; report->reset(upload_report.release()); } @@ -761,7 +764,9 @@ const std::string& id) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - Metrics::CrashUploadAttempted(successful); + if (report->report_metrics_) { + Metrics::CrashUploadAttempted(successful); + } std::unique_ptr<Metadata> metadata(AcquireMetadata()); if (!metadata)
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_fuchsia.cc b/third_party/crashpad/crashpad/client/crashpad_client_fuchsia.cc index 26781094..0d1b65b 100644 --- a/third_party/crashpad/crashpad/client/crashpad_client_fuchsia.cc +++ b/third_party/crashpad/crashpad/client/crashpad_client_fuchsia.cc
@@ -58,14 +58,8 @@ return false; } - std::vector<std::string> argv_strings; - BuildHandlerArgvStrings(handler, - database, - metrics_dir, - url, - annotations, - arguments, - &argv_strings); + std::vector<std::string> argv_strings = BuildHandlerArgvStrings( + handler, database, metrics_dir, url, annotations, arguments); std::vector<const char*> argv; ConvertArgvStrings(argv_strings, &argv);
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc index e7fa162c..54fe268 100644 --- a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc +++ b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
@@ -175,9 +175,8 @@ const std::string& url, const std::map<std::string, std::string>& annotations, const std::vector<std::string>& arguments) { - std::vector<std::string> argv; - BuildHandlerArgvStrings( - handler, database, metrics_dir, url, annotations, arguments, &argv); + std::vector<std::string> argv = BuildHandlerArgvStrings( + handler, database, metrics_dir, url, annotations, arguments); auto signal_handler = LaunchAtCrashHandler::Get(); if (signal_handler->Initialize(&argv)) { @@ -197,9 +196,8 @@ const std::map<std::string, std::string>& annotations, const std::vector<std::string>& arguments, int socket) { - std::vector<std::string> argv; - BuildHandlerArgvStrings( - handler, database, metrics_dir, url, annotations, arguments, &argv); + std::vector<std::string> argv = BuildHandlerArgvStrings( + handler, database, metrics_dir, url, annotations, arguments); argv.push_back(FormatArgumentInt("initial-client", socket));
diff --git a/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc b/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc index e1be2f4..27a2836 100644 --- a/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc +++ b/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc
@@ -41,9 +41,10 @@ MOCK_METHOD2(LookUpCrashReport, OperationStatus(const UUID&, Report*)); MOCK_METHOD1(GetPendingReports, OperationStatus(std::vector<Report>*)); MOCK_METHOD1(GetCompletedReports, OperationStatus(std::vector<Report>*)); - MOCK_METHOD2(GetReportForUploading, + MOCK_METHOD3(GetReportForUploading, OperationStatus(const UUID&, - std::unique_ptr<const UploadReport>*)); + std::unique_ptr<const UploadReport>*, + bool report_metrics)); MOCK_METHOD3(RecordUploadAttempt, OperationStatus(UploadReport*, bool, const std::string&)); MOCK_METHOD2(SkipReportUpload,
diff --git a/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc b/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc index 5fdeb5b..7af51a27 100644 --- a/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc +++ b/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc
@@ -115,8 +115,7 @@ // Add a bunch of values to the dictionary, remove some entries in the middle, // and then add more. TEST(SimpleStringDictionary, Iterator) { - SimpleStringDictionary* dict = new SimpleStringDictionary; - ASSERT_TRUE(dict); + SimpleStringDictionary dict; char key[SimpleStringDictionary::key_size]; char value[SimpleStringDictionary::value_size]; @@ -135,32 +134,32 @@ for (int i = 0; i < kPartitionIndex; ++i) { sprintf(key, "key%d", i); sprintf(value, "value%d", i); - dict->SetKeyValue(key, value); + dict.SetKeyValue(key, value); } expected_dictionary_size = kPartitionIndex; // set a couple of the keys twice (with the same value) - should be nop - dict->SetKeyValue("key2", "value2"); - dict->SetKeyValue("key4", "value4"); - dict->SetKeyValue("key15", "value15"); + dict.SetKeyValue("key2", "value2"); + dict.SetKeyValue("key4", "value4"); + dict.SetKeyValue("key15", "value15"); // Remove some random elements in the middle - dict->RemoveKey("key7"); - dict->RemoveKey("key18"); - dict->RemoveKey("key23"); - dict->RemoveKey("key31"); + dict.RemoveKey("key7"); + dict.RemoveKey("key18"); + dict.RemoveKey("key23"); + dict.RemoveKey("key31"); expected_dictionary_size -= 4; // we just removed four key/value pairs // Set some more key/value pairs like key59/value59, key60/value60, ... for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) { sprintf(key, "key%d", i); sprintf(value, "value%d", i); - dict->SetKeyValue(key, value); + dict.SetKeyValue(key, value); } expected_dictionary_size += kDictionaryCapacity - kPartitionIndex; // Now create an iterator on the dictionary - SimpleStringDictionary::Iterator iter(*dict); + SimpleStringDictionary::Iterator iter(dict); // We then verify that it iterates through exactly the number of key/value // pairs we expect, and that they match one-for-one with what we would expect.
diff --git a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc index 4783ecb..205d860 100644 --- a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc +++ b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
@@ -227,6 +227,10 @@ database_->RecordUploadComplete(std::move(upload_report), response_body); break; case UploadResult::kPermanentFailure: + upload_report.reset(); + database_->SkipReportUpload( + report.uuid, Metrics::CrashSkippedReason::kPrepareForUploadFailed); + break; case UploadResult::kRetry: upload_report.reset();
diff --git a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc index 6c0b98a..940114c6 100644 --- a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc +++ b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux_test.cc
@@ -40,6 +40,7 @@ #include "test/multiprocess.h" #include "util/file/file_io.h" #include "util/linux/direct_ptrace_connection.h" +#include "util/misc/address_sanitizer.h" #include "util/misc/from_pointer_cast.h" #include "util/synchronization/semaphore.h" @@ -264,12 +265,17 @@ iterator->second.tls); ASSERT_TRUE(memory_map.FindMapping(thread.stack_region_address)); - EXPECT_LE(thread.stack_region_address, iterator->second.stack_address); - ASSERT_TRUE(memory_map.FindMapping(thread.stack_region_address + thread.stack_region_size - 1)); + +#if !defined(ADDRESS_SANITIZER) + // AddressSanitizer causes stack variables to be stored separately from the + // call stack. + EXPECT_LE(thread.stack_region_address, iterator->second.stack_address); EXPECT_GE(thread.stack_region_address + thread.stack_region_size, iterator->second.stack_address); +#endif // !defined(ADDRESS_SANITIZER) + if (iterator->second.max_stack_size) { EXPECT_LT(thread.stack_region_size, iterator->second.max_stack_size); }
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc index 1be829d..478b37d 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc
@@ -15,6 +15,7 @@ #include "snapshot/mac/mach_o_image_segment_reader.h" #include <mach-o/loader.h> +#include <string.h> #include <utility> @@ -35,6 +36,37 @@ } // namespace +bool IsMalformedCLKernelsModule(uint32_t mach_o_file_type, + const std::string& module_name, + bool* has_timestamp) { + if (mach_o_file_type != MH_BUNDLE) { + return false; + } + + if (module_name == "cl_kernels") { + if (MacOSXMinorVersion() >= 10) { + if (has_timestamp) { + *has_timestamp = false; + } + return true; + } + return false; + } + + static const char kCvmsObjectPathPrefix[] = + "/private/var/db/CVMS/cvmsCodeSignObj"; + if (module_name.compare( + 0, strlen(kCvmsObjectPathPrefix), kCvmsObjectPathPrefix) == 0 && + MacOSXMinorVersion() >= 14) { + if (has_timestamp) { + *has_timestamp = true; + } + return true; + } + + return false; +} + MachOImageSegmentReader::MachOImageSegmentReader() : segment_command_(), sections_(), @@ -121,21 +153,13 @@ load_command_info.c_str()); // cl_kernels modules (for OpenCL) aren’t ld output, and they’re formatted - // incorrectly on OS X 10.10 and later. They have a single __TEXT segment, - // but one of the sections within it claims to belong to the __LD segment. - // This mismatch shouldn’t happen. This errant section also has the - // S_ATTR_DEBUG flag set, which shouldn’t happen unless all of the other - // sections in the segment also have this bit set (they don’t). These odd - // sections are reminiscent of unwind information stored in MH_OBJECT - // images, although cl_kernels images claim to be MH_BUNDLE. Because at - // least one cl_kernels module will commonly be found in a process, and - // sometimes more will be, tolerate this quirk. + // incorrectly on OS X 10.10 and later. Because at least one cl_kernels + // module will commonly be found in a process, and sometimes more will be, + // tolerate this quirk. // // https://openradar.appspot.com/20239912 if (section_segment_name != segment_name && - !(file_type == MH_BUNDLE && - module_name == "cl_kernels" && - MacOSXMinorVersion() >= 10 && + !(IsMalformedCLKernelsModule(file_type, module_name, nullptr) && segment_name == SEG_TEXT && section_segment_name == "__LD" && section_name == "__compact_unwind" &&
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h index bdd5771..1e72785 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h +++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h
@@ -29,6 +29,41 @@ namespace crashpad { +//! \brief Determines whether a module appears to be a malformed OpenCL +//! `cl_kernels` module based on its name and Mach-O file type. +//! +//! `cl_kernels` modules require special handling because they’re malformed on +//! OS X 10.10 and later. A `cl_kernels` module always has Mach-O type +//! `MH_BUNDLE` and is named `"cl_kernels"` until macOS 10.14, and +//! `"/private/var/db/CVMS/cvmsCodeSignObj"` plus 16 random characters on macOS +//! 10.14. +//! +//! Malformed `cl_kernels` modules have a single `__TEXT` segment, but one of +//! the sections within it claims to belong to the `__LD` segment. This mismatch +//! shouldn’t happen. This errant section also has the `S_ATTR_DEBUG` flag set, +//! which shouldn’t happen unless all of the other sections in the segment also +//! have this bit set (they don’t). These odd sections are reminiscent of unwind +//! information stored in `MH_OBJECT` images, although `cl_kernels` images claim +//! to be `MH_BUNDLE`. +//! +//! This function is exposed for testing purposes only. +//! +//! \param[in] mach_o_file_type The Mach-O type of the module being examined. +//! \param[in] module_name The pathname that `dyld` reported having loaded the +//! module from. +//! \param[out] has_timestamp Optional, may be `nullptr`. If provided, and the +//! module is a maformed `cl_kernels` module, this will be set to `true` if +//! the module was loaded from the filesystem (as is the case when loaded +//! from the CVMS directory) and is expected to have a timestamp, and +//! `false` otherwise. Note that even when loaded from the filesystem, these +//! modules are unlinked from the filesystem after loading. +//! +//! \return `true` if the module appears to be a malformed `cl_kernels` module +//! based on the provided information, `false` otherwise. +bool IsMalformedCLKernelsModule(uint32_t mach_o_file_type, + const std::string& module_name, + bool* has_timestamp); + //! \brief A reader for `LC_SEGMENT` or `LC_SEGMENT_64` load commands in Mach-O //! images mapped into another process. //!
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc index faec147..59884a6 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc
@@ -32,6 +32,7 @@ #include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/mac/mach_o_image_reader.h" +#include "snapshot/mac/mach_o_image_segment_reader.h" #include "test/errors.h" #include "test/mac/dyld.h" #include "test/mac/mach_errors.h" @@ -663,14 +664,20 @@ modules[index].reader->Address(), FromPointerCast<mach_vm_address_t>(_dyld_get_image_header(index))); + bool expect_timestamp; if (index == 0) { // dyld didn’t load the main executable, so it couldn’t record its // timestamp, and it is reported as 0. EXPECT_EQ(modules[index].timestamp, 0); - } else if (modules[index].reader->FileType() == MH_BUNDLE && - modules[index].name == "cl_kernels") { - // cl_kernels doesn’t exist as a file. - EXPECT_EQ(modules[index].timestamp, 0); + } else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(), + modules[index].name, + &expect_timestamp)) { + // cl_kernels doesn’t exist as a file, but may still have a timestamp. + if (!expect_timestamp) { + EXPECT_EQ(modules[index].timestamp, 0); + } else { + EXPECT_NE(modules[index].timestamp, 0); + } found_cl_kernels = true; } else { // Hope that the module didn’t change on disk. @@ -747,14 +754,20 @@ ASSERT_TRUE(modules[index].reader); EXPECT_EQ(modules[index].reader->Address(), expect_address); + bool expect_timestamp; if (index == 0 || index == modules.size() - 1) { // dyld didn’t load the main executable or itself, so it couldn’t record // these timestamps, and they are reported as 0. EXPECT_EQ(modules[index].timestamp, 0); - } else if (modules[index].reader->FileType() == MH_BUNDLE && - modules[index].name == "cl_kernels") { - // cl_kernels doesn’t exist as a file. - EXPECT_EQ(modules[index].timestamp, 0); + } else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(), + modules[index].name, + &expect_timestamp)) { + // cl_kernels doesn’t exist as a file, but may still have a timestamp. + if (!expect_timestamp) { + EXPECT_EQ(modules[index].timestamp, 0); + } else { + EXPECT_NE(modules[index].timestamp, 0); + } found_cl_kernels = true; } else { // Hope that the module didn’t change on disk.
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.cc b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.cc index 90bfac54..652e0e4 100644 --- a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.cc +++ b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.cc
@@ -31,6 +31,7 @@ crashpad_info_(), annotations_simple_map_(), file_reader_(nullptr), + process_id_(static_cast<pid_t>(-1)), initialized_() { } @@ -83,19 +84,19 @@ stream_map_[stream_type] = &directory.Location; } - INITIALIZATION_STATE_SET_VALID(initialized_); - - if (!InitializeCrashpadInfo()) { + if (!InitializeCrashpadInfo() || + !InitializeMiscInfo() || + !InitializeModules()) { return false; } - return InitializeModules(); + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; } pid_t ProcessSnapshotMinidump::ProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return 0; + return process_id_; } pid_t ProcessSnapshotMinidump::ParentProcessID() const { @@ -234,6 +235,45 @@ &annotations_simple_map_); } +bool ProcessSnapshotMinidump::InitializeMiscInfo() { + const auto& stream_it = stream_map_.find(kMinidumpStreamTypeMiscInfo); + if (stream_it == stream_map_.end()) { + return true; + } + + if (!file_reader_->SeekSet(stream_it->second->Rva)) { + return false; + } + + const size_t size = stream_it->second->DataSize; + if (size != sizeof(MINIDUMP_MISC_INFO_5) && + size != sizeof(MINIDUMP_MISC_INFO_4) && + size != sizeof(MINIDUMP_MISC_INFO_3) && + size != sizeof(MINIDUMP_MISC_INFO_2) && + size != sizeof(MINIDUMP_MISC_INFO)) { + LOG(ERROR) << "misc_info size mismatch"; + return false; + } + + MINIDUMP_MISC_INFO_5 info; + if (!file_reader_->ReadExactly(&info, size)) { + return false; + } + + switch (stream_it->second->DataSize) { + case sizeof(MINIDUMP_MISC_INFO_5): + case sizeof(MINIDUMP_MISC_INFO_4): + case sizeof(MINIDUMP_MISC_INFO_3): + case sizeof(MINIDUMP_MISC_INFO_2): + case sizeof(MINIDUMP_MISC_INFO): + // TODO(jperaza): Save the remaining misc info. + // https://crashpad.chromium.org/bug/10 + process_id_ = info.ProcessId; + } + + return true; +} + bool ProcessSnapshotMinidump::InitializeModules() { const auto& stream_it = stream_map_.find(kMinidumpStreamTypeModuleList); if (stream_it == stream_map_.end()) {
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h index 211805e..9ba5d9c 100644 --- a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h +++ b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h
@@ -92,6 +92,10 @@ std::map<uint32_t, MINIDUMP_LOCATION_DESCRIPTOR>* module_crashpad_info_links); + // Initializes data carried in a MINIDUMP_MISC_INFO structure on behalf of + // Initialize(). + bool InitializeMiscInfo(); + MINIDUMP_HEADER header_; std::vector<MINIDUMP_DIRECTORY> stream_directory_; std::map<MinidumpStreamType, const MINIDUMP_LOCATION_DESCRIPTOR*> stream_map_; @@ -100,6 +104,7 @@ MinidumpCrashpadInfo crashpad_info_; std::map<std::string, std::string> annotations_simple_map_; FileReaderInterface* file_reader_; // weak + pid_t process_id_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ProcessSnapshotMinidump);
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc index 82e14a7a..ed17939 100644 --- a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc
@@ -420,6 +420,38 @@ EXPECT_EQ(annotation_objects, annotations_4); } +TEST(ProcessSnapshotMinidump, ProcessID) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + ASSERT_TRUE(string_file.Write(&header, sizeof(header))); + + static const pid_t kTestProcessId = 42; + MINIDUMP_MISC_INFO misc_info = {}; + misc_info.SizeOfInfo = sizeof(misc_info); + misc_info.Flags1 = MINIDUMP_MISC1_PROCESS_ID; + misc_info.ProcessId = kTestProcessId; + + MINIDUMP_DIRECTORY misc_directory = {}; + misc_directory.StreamType = kMinidumpStreamTypeMiscInfo; + misc_directory.Location.DataSize = sizeof(misc_info); + misc_directory.Location.Rva = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&misc_info, sizeof(misc_info))); + + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&misc_directory, sizeof(misc_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + ASSERT_TRUE(string_file.SeekSet(0)); + ASSERT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + ASSERT_TRUE(process_snapshot.Initialize(&string_file)); + EXPECT_EQ(process_snapshot.ProcessID(), kTestProcessId); +} + } // namespace } // namespace test } // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc b/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc index 485ef87..cb413e3b 100644 --- a/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc +++ b/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc
@@ -19,6 +19,7 @@ #include "gtest/gtest.h" #include "test/multiprocess_exec.h" #include "util/file/file_io.h" +#include "util/misc/address_sanitizer.h" #include "util/numeric/safe_assignment.h" #if defined(OS_LINUX) || defined(OS_ANDROID) @@ -162,6 +163,23 @@ // MemorySnapshot::Delegate bool MemorySnapshotDelegateRead(void* data, size_t size) override { +#if defined(ADDRESS_SANITIZER) && (defined(OS_LINUX) || defined(OS_ANDROID)) + // AddressSanitizer causes stack variables to be stored separately from the + // call stack. + auto addr_not_in_stack_range = + [](VMAddress addr, VMAddress stack_addr, VMSize stack_size) { + return addr < stack_addr || addr >= stack_addr + stack_size; + }; + EXPECT_PRED3(addr_not_in_stack_range, + addrs_.code_pointer_address, + stack_->Address(), + size); + EXPECT_PRED3(addr_not_in_stack_range, + addrs_.string_address, + stack_->Address(), + size); + return true; +#else size_t pointer_offset; if (!AssignIfInRange(&pointer_offset, addrs_.code_pointer_address - stack_->Address())) { @@ -192,6 +210,7 @@ EXPECT_STREQ(string, kSensitiveStackData); } return true; +#endif // ADDRESS_SANITIZER && (OS_LINUX || OS_ANDROID) } private:
diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_test.cc b/third_party/crashpad/crashpad/util/misc/capture_context_test.cc index 1117789d..7f3890f1 100644 --- a/third_party/crashpad/crashpad/util/misc/capture_context_test.cc +++ b/third_party/crashpad/crashpad/util/misc/capture_context_test.cc
@@ -60,12 +60,16 @@ kReferencePC); #endif // !defined(ADDRESS_SANITIZER) - // Declare sp and context_2 here because all local variables need to be - // declared before computing the stack pointer reference value, so that the - // reference value can be the lowest value possible. - uintptr_t sp; + const uintptr_t sp = StackPointerFromContext(context_1); + + // Declare context_2 here because all local variables need to be declared + // before computing the stack pointer reference value, so that the reference + // value can be the lowest value possible. NativeCPUContext context_2; +// AddressSanitizer on Linux causes stack variables to be stored separately from +// the call stack. +#if !defined(ADDRESS_SANITIZER) || (!defined(OS_LINUX) && !defined(OS_ANDROID)) // The stack pointer reference value is the lowest address of a local variable // in this function. The captured program counter will be slightly less than // or equal to the reference stack pointer. @@ -74,11 +78,11 @@ reinterpret_cast<uintptr_t>(&context_2)), std::min(reinterpret_cast<uintptr_t>(&pc), reinterpret_cast<uintptr_t>(&sp))); - sp = StackPointerFromContext(context_1); EXPECT_PRED2([](uintptr_t actual, uintptr_t reference) { return reference - actual < 768u; }, sp, kReferenceSP); +#endif // !ADDRESS_SANITIZER || (!OS_LINUX && !OS_ANDROID) // Capture the context again, expecting that the stack pointer stays the same // and the program counter increases. Strictly speaking, there’s no guarantee
diff --git a/third_party/crashpad/crashpad/util/misc/metrics.h b/third_party/crashpad/crashpad/util/misc/metrics.h index 3e9337a..8046497 100644 --- a/third_party/crashpad/crashpad/util/misc/metrics.h +++ b/third_party/crashpad/crashpad/util/misc/metrics.h
@@ -77,6 +77,10 @@ //! server. kUploadFailed = 4, + //! \brief There was an error between accessing the report from the database + //! and uploading it to the crash server. + kPrepareForUploadFailed = 5, + //! \brief The number of values in this enumeration; not a valid value. kMaxValue };
diff --git a/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c b/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c index 5c65a035..16bef1e3 100644 --- a/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c +++ b/third_party/tcmalloc/chromium/src/windows/addr2line-pdb.c
@@ -35,9 +35,17 @@ * c:\websymbols without asking. */ +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE +#endif #include <stdio.h> #include <stdlib.h> @@ -93,7 +101,7 @@ if (!SymInitialize(process, NULL, FALSE)) { error = GetLastError(); - fprintf(stderr, "SymInitialize returned error : %d\n", error); + fprintf(stderr, "SymInitialize returned error : %lu\n", error); return 1; } @@ -107,13 +115,13 @@ strcat(search, ";" WEBSYM); } else { error = GetLastError(); - fprintf(stderr, "SymGetSearchPath returned error : %d\n", error); + fprintf(stderr, "SymGetSearchPath returned error : %lu\n", error); rv = 1; /* An error, but not a fatal one */ strcpy(search, WEBSYM); /* Use a default value */ } if (!SymSetSearchPath(process, search)) { error = GetLastError(); - fprintf(stderr, "SymSetSearchPath returned error : %d\n", error); + fprintf(stderr, "SymSetSearchPath returned error : %lu\n", error); rv = 1; /* An error, but not a fatal one */ } @@ -122,7 +130,7 @@ if (!module_base) { /* SymLoadModuleEx failed */ error = GetLastError(); - fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n", + fprintf(stderr, "SymLoadModuleEx returned error : %lu for %s\n", error, filename); SymCleanup(process); return 1;
diff --git a/tools/binary_size/libsupersize/html_report.py b/tools/binary_size/libsupersize/html_report.py index e6bbb0e1..25cc18e5 100644 --- a/tools/binary_size/libsupersize/html_report.py +++ b/tools/binary_size/libsupersize/html_report.py
@@ -27,6 +27,7 @@ _COMPACT_SYMBOL_BYTE_SIZE_KEY = 'b' _COMPACT_SYMBOL_TYPE_KEY = 't' _COMPACT_SYMBOL_COUNT_KEY = 'u' +_COMPACT_SYMBOL_FLAGS_KEY = 'f' _SMALL_SYMBOL_DESCRIPTIONS = { 'b': 'Other small uninitialized data', @@ -34,7 +35,6 @@ 'r': 'Other small readonly data', 't': 'Other small code', 'v': 'Other small vtable entries', - '*': 'Other small generated symbols', 'x': 'Other small dex non-method entries', 'm': 'Other small dex methods', 'p': 'Other small locale pak entries', @@ -49,8 +49,6 @@ symbol_type = symbol.section if symbol.name.endswith('[vtable]'): symbol_type = _SYMBOL_TYPE_VTABLE - elif symbol.name.endswith(']'): - symbol_type = _SYMBOL_TYPE_GENERATED if symbol_type not in _SMALL_SYMBOL_DESCRIPTIONS: symbol_type = _SYMBOL_TYPE_OTHER return symbol_type @@ -147,6 +145,8 @@ # so this data is only included for methods. if is_dex_method and symbol_count != 1: symbol_entry[_COMPACT_SYMBOL_COUNT_KEY] = symbol_count + if symbol.flags: + symbol_entry[_COMPACT_SYMBOL_FLAGS_KEY] = symbol.flags file_node[_COMPACT_FILE_SYMBOLS_KEY].append(symbol_entry) for symbol in extra_symbols:
diff --git a/tools/binary_size/libsupersize/models.py b/tools/binary_size/libsupersize/models.py index 3126088d..39107bd 100644 --- a/tools/binary_size/libsupersize/models.py +++ b/tools/binary_size/libsupersize/models.py
@@ -138,6 +138,9 @@ # which was removed by name normalization. Occurs when an AFDO profile is # supplied to the linker. FLAG_HOT = 128 +# Relevant for .text symbols. If a method has this flag, then it was run +# according to the code coverage. +FLAG_COVERED = 256 DIFF_STATUS_UNCHANGED = 0
diff --git a/tools/binary_size/libsupersize/static/index.html b/tools/binary_size/libsupersize/static/index.html index 9e176e1..d7c644a 100644 --- a/tools/binary_size/libsupersize/static/index.html +++ b/tools/binary_size/libsupersize/static/index.html
@@ -34,6 +34,7 @@ align-items: center; } .appbar-progress { + box-sizing: border-box; display: block; width: 100%; height: 4px; @@ -140,6 +141,7 @@ .icon { display: block; margin-right: 6px; + flex: none; } /** Tree nodes */ @@ -179,13 +181,13 @@ .symbol-name { font-weight: 500; word-break: break-word; - flex: 1; } .count, .size, .percent { - margin-left: 16px; + margin-left: auto; + padding-left: 16px; text-align: right; color: #5f6368; white-space: nowrap; @@ -200,6 +202,16 @@ text-decoration: line-through; } + .highlight { + background: #feefc3; + } + .highlight-positive { + background: #ceead6; + } + .highlight-negative { + background: #fad2cf; + } + .diff .size-header::after { content: " diff"; } @@ -220,6 +232,7 @@ <body> <div class="scrim toggle-options" hidden></div> + <!-- App Toolbar --> <header class="appbar"> <div class="appbar-inner"> <h1 class="headline">Super Size Tiger View</h1> @@ -234,7 +247,8 @@ </svg> <span class="label-text">Upload data</span> </label> - <a href="https://chromium.googlesource.com/chromium/src/+/master/tools/binary_size/html_report_faq.md" class="icon-button" title="FAQ" id="faq"> + <a href="https://chromium.googlesource.com/chromium/src/+/master/tools/binary_size/html_report_faq.md" class="icon-button" + title="FAQ" id="faq"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#5f6368"> <path d="M11,18h2v-2h-2V18z M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z M12,20c-4.41,0-8-3.59-8-8 s3.59-8,8-8s8,3.59,8,8S16.41,20,12,20z M12,6c-2.21,0-4,1.79-4,4h2c0-1.1,0.9-2,2-2s2,0.9,2,2c0,2-3,1.75-3,5h2c0-2.25,3-2.5,3-5 @@ -264,7 +278,7 @@ </div> <progress value="0" id="progress" class="appbar-progress"></progress> </header> - <link href="options.css" rel="stylesheet"> + <!-- Options side panel --> <form id="options" class="options" method="GET"> <header class="form-bar"> <button type="button" class="icon-button toggle-options" title="Close"> @@ -319,9 +333,9 @@ <p class="input-error" id="include-error"></p> </div> <div class="input-wrapper"> - <input class="input-regex" type="text" id="excluderegex" name="exclude" placeholder="\(.+\)" aria-describedby="exclude-error"> + <input class="input-regex" type="text" id="excluderegex" name="exclude" placeholder="\(.+\)" aria-describedby="exclude-error"> <label class="input-label" for="excluderegex"> - Symbols must exclude + Symbols must exclude </label> <p class="input-error" id="exclude-error"></p> </div> @@ -360,12 +374,6 @@ </label> </div> <div class="checkbox-wrapper"> - <input type="checkbox" id="filtergen" name="type" value="*" checked> - <label class="checkbox-label" for="filtergen"> - Generated Symbols (typeinfo, thunks, etc) - </label> - </div> - <div class="checkbox-wrapper"> <input type="checkbox" id="filterdexnon" name="type" value="x" checked> <label class="checkbox-label" for="filterdexnon"> Dex non-method entries @@ -398,8 +406,34 @@ <button type="button" class="text-button" id="type-all">Select all</button> <button type="button" class="text-button" id="type-none">Select none</button> </fieldset> + + <fieldset id="highlight-container"> + <legend class="subhead">Highlight symbols</legend> + <div class="radio-wrapper"> + <input type="radio" id="clearhighlight" name="highlight" value="clear" checked> + <label class="radio-label" for="clearhighlight">None</label> + </div> + <div class="radio-wrapper"> + <input type="radio" id="hothighlight" name="highlight" value="hot"> + <label class="radio-label" for="hothighlight">Hot code</label> + </div> + <div class="radio-wrapper"> + <input type="radio" id="generatedhighlight" name="highlight" value="generated"> + <label class="radio-label" for="generatedhighlight">Generated files</label> + </div> + <div class="radio-wrapper"> + <input type="radio" id="coveragehightlight" name="highlight" value="coverage"> + <label class="radio-label" for="coveragehightlight">Code coverage</label> + </div> + </fieldset> + + <div class="checkbox-wrapper"> + <input type="checkbox" id="generatedfilter" name="generated_filter" value="on"> + <label class="checkbox-label" for="generatedfilter">Show only generated files</label> + </div> </form> <div class="symbols"> + <!-- Icons for symbols are stored here and cloned. --> <div hidden id="icons"> <svg class="icon foldericon" height="24" width="24" fill="#5f6368"> <title>Directory</title> @@ -449,11 +483,6 @@ <path d="M20,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h15c1.1,0,2-0.9,2-2V5C22,3.9,21.1,3,20,3z M20,5v3H5V5H20z M15,19h-5v-9h5V19z M5,10h3v9H5V10z M17,19v-9h3v9H17z" /> </svg> - <svg class="icon generatedicon" height="24" width="24" fill="#f439a0"> - <title>Generated symbol</title> - <path d="M6 2a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V8l-6-6H6zm0 2h7v5h5v11H6V4zm9.5 8l-.6 1.4-1.4.6 1.4.6.6 1.4.6-1.4 1.4-.6-1.4-.6-.6-1.4zm-6 1l-1 2-2 1 2 1 1 2 1-2 2-1-2-1-1-2z" - /> - </svg> <svg class="icon dexicon" height="24" width="24" fill="#ea4335"> <title>Dex non-method entry</title> <path d="M6.6 1.44l-.82.83 2.1 2.1A6.96 6.96 0 0 0 5 10v1h14v-1a6.96 6.96 0 0 0-2.88-5.63l2.1-2.1-.82-.83-2.3 2.31a6.81 6.81 0 0 0-6.19 0L6.6 1.44zM9 7a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zM5 12v4.27C5 20 8.17 23 12 23s7-3 7-6.73V12H5zm2 2h10v2.27c0 2.6-2.2 4.73-5 4.73s-5-2.13-5-4.73V14z" @@ -480,6 +509,7 @@ /> </svg> </div> + <!-- Template for trees and leaves --> <template id="treenode-container"> <li role="treeitem" aria-expanded="false" aria-describedby="infocard-container"> <a class="node" href="#" tabindex="-1" role="presentation"> @@ -497,6 +527,7 @@ </span> </li> </template> + <!-- Tree view --> <main class="tree-container"> <header class="tree-header"> <span class="subtitle">Name</span> @@ -504,6 +535,7 @@ </header> <ul id="symboltree" class="tree" role="tree" aria-labelledby="headline"></ul> </main> + <!-- Symbol and container breakdown cards --> <link href="infocard.css" rel="stylesheet"> <footer class="infocards"> <div class="infocard infocard-container open" id="infocard-container" hidden> @@ -514,11 +546,12 @@ <header class="header-info"> <h4 class="subhead size-info"></h4> <p class="body-2 path-info"></p> - <p class="caption type-info"></p> + <p class="caption type-info type-info-container"></p> </header> <table class="type-breakdown-info"> <thead> <tr> + <th class="subhead-2">Icon</th> <th class="subhead-2">Type</th> <th class="subhead-2 count">Count</th> <th class="subhead-2 size">Total size</th> @@ -527,66 +560,118 @@ </thead> <tbody> <tr class="bss-info"> + <td> + <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#a142f4"> + <path d="M6 2a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V8l-6-6H6zm0 2h7v5h5v11H6V4zm4 6v4h2v-4h-2zm0 6v2h2v-2h-2z" + /> + </svg> + </td> <th scope="row">.bss</th> <td class="count"></td> <td class="size"></td> <td class="percent"></td> </tr> <tr class="data-info"> + <td> + <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#fa7b17"> + <path d="M6 2a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6H6m0 2h7v5h5v11H6V4m2 8v2h8v-2H8m0 4v2h5v-2z" /> + </svg> + </td> <th scope="row">.data and .data.*</th> <td class="count"></td> <td class="size"></td> <td class="percent"></td> </tr> <tr class="rodata-info"> + <td> + <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#24c1e0"> + <path d="M6 2a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V8l-6-6H6zm0 2h7v5h5v11H6V4zm5.9 8c-2 0-3.7 1.2-4.4 3a4.7 4.7 0 0 0 8.8 0c-.7-1.8-2.4-3-4.4-3zm0 1a2 2 0 0 1 2 2 2 2 0 0 1-2 2 2 2 0 0 1-2-2 2 2 0 0 1 2-2zm0 .8a1.2 1.2 0 0 0-1.2 1.2 1.2 1.2 0 0 0 1.2 1.2 1.2 1.2 0 0 0 1.2-1.2 1.2 1.2 0 0 0-1.2-1.2z" + /> + </svg> + </td> <th scope="row">.rodata</th> <td class="count"></td> <td class="size"></td> <td class="percent"></td> </tr> <tr class="text-info"> + <td> + <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#1a73e8"> + <path d="M9.4,16.6L4.8,12l4.6-4.6L8,6l-6,6l6,6L9.4,16.6z M14.6,16.6l4.6-4.6l-4.6-4.6L16,6l6,6l-6,6L14.6,16.6z" /> + </svg> + </td> <th scope="row">.text</th> <td class="count"></td> <td class="size"></td> <td class="percent"></td> </tr> <tr class="vtable-info"> + <td> + <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#fbbc04"> + <path d="M20,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h15c1.1,0,2-0.9,2-2V5C22,3.9,21.1,3,20,3z M20,5v3H5V5H20z M15,19h-5v-9h5V19z + M5,10h3v9H5V10z M17,19v-9h3v9H17z" /> + </svg> + </td> <th scope="row">Vtable entry</th> <td class="count"></td> <td class="size"></td> <td class="percent"></td> </tr> - <tr class="gen-info"> - <th scope="row">Generated symbols</th> - <td class="count"></td> - <td class="size"></td> - <td class="percent"></td> - </tr> <tr class="dexnon-info"> + <td> + <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#ea4335"> + <path d="M6.6 1.44l-.82.83 2.1 2.1A6.96 6.96 0 0 0 5 10v1h14v-1a6.96 6.96 0 0 0-2.88-5.63l2.1-2.1-.82-.83-2.3 2.31a6.81 6.81 0 0 0-6.19 0L6.6 1.44zM9 7a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zM5 12v4.27C5 20 8.17 23 12 23s7-3 7-6.73V12H5zm2 2h10v2.27c0 2.6-2.2 4.73-5 4.73s-5-2.13-5-4.73V14z" + /> + </svg> + </td> <th scope="row">Dex non-method entries</th> <td class="count"></td> <td class="size"></td> <td class="percent"></td> </tr> <tr class="dex-info"> + <td> + <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#a50e0e"> + <path d="M6.6 1.44l-.82.83 2.1 2.1A6.96 6.96 0 0 0 5 10v1h14v-1a6.96 6.96 0 0 0-2.88-5.63l2.1-2.1-.82-.83-2.3 2.31a6.81 6.81 0 0 0-6.19 0L6.6 1.44zM9 7a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zM5 12v4.27C5 20 8.17 23 12 23s7-3 7-6.73V12H5zm2 2h10v2.27c0 2.6-2.2 4.73-5 4.73s-5-2.13-5-4.73V14z" + /> + </svg> + </td> <th scope="row">Dex methods</th> <td class="count"></td> <td class="size"></td> <td class="percent"></td> </tr> <tr class="pak-info"> + <td> + <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#34a853"> + <path d="M5 3a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H5zm0 2h5v2h2V5h7v14H5V5zm7 2v2h2V7h-2zm0 2h-2v2h2V9zm0 2v2h2v-2h-2zm0 2h-2v2h2v-2zm0 2v2h2v-2h-2z" + /> + </svg> + </td> <th scope="row">Locale pak entries</th> <td class="count"></td> <td class="size"></td> <td class="percent"></td> </tr> <tr class="paknon-info"> + <td> + <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#0d652d"> + <path d="M5 3a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H5zm0 2h5v2h2V5h7v14H5V5zm7 2v2h2V7h-2zm0 2h-2v2h2V9zm0 2v2h2v-2h-2zm0 2h-2v2h2v-2zm0 2v2h2v-2h-2z" + /> + </svg> + </td> <th scope="row">Non-locale pak entries</th> <td class="count"></td> <td class="size"></td> <td class="percent"></td> </tr> <tr class="other-info"> + <td> + <svg class="icon" viewBox="0 0 24 24" height="18" width="18" fill="#5f6368"> + <path d="M10.88 2l-.85 1.36L4 13h6v-2H7.6l3.28-5.23L12.28 8h2.35l-3.75-6zM12 10v10h10V10H12zm2 2h6v6h-6v-6zM2.21 15A5.52 5.52 0 0 0 10 21.4v-2.45A3.48 3.48 0 0 1 7.5 20a3.48 3.48 0 0 1-3.15-5H2.2z" + /> + </svg> + </td> <th scope="row">Other entries</th> <td class="count"></td> <td class="size"></td> @@ -596,14 +681,17 @@ </table> </div> <div class="infocard infocard-symbol" id="infocard-symbol" hidden> - <div class="icon-info"> - <div></div> - </div> + <div class="icon-info"> + <div></div> + </div> <header class="header-info"> <h4 class="subhead size-info"></h4> <p class="body-2 path-info"></p> </header> - <p class="caption type-info"></p> + <p class="caption type-info-container"> + <span class="type-info"></span> + <span class="flags-info"></span> + </p> </div> </footer> </div>
diff --git a/tools/binary_size/libsupersize/static/infocard-ui.js b/tools/binary_size/libsupersize/static/infocard-ui.js index 7d04641..b244a04 100644 --- a/tools/binary_size/libsupersize/static/infocard-ui.js +++ b/tools/binary_size/libsupersize/static/infocard-ui.js
@@ -14,6 +14,18 @@ const displayInfocard = (() => { const _CANVAS_RADIUS = 40; + const _FLAG_LABELS = new Map([ + [_FLAGS.ANONYMOUS, 'anon'], + [_FLAGS.STARTUP, 'startup'], + [_FLAGS.UNLIKELY, 'unlikely'], + [_FLAGS.REL, 'rel'], + [_FLAGS.REL_LOCAL, 'rel.loc'], + [_FLAGS.GENERATED_SOURCE, 'gen'], + [_FLAGS.CLONE, 'clone'], + [_FLAGS.HOT, 'hot'], + [_FLAGS.COVERAGE, 'covered'], + ]); + class Infocard { /** * @param {string} id @@ -26,7 +38,7 @@ this._pathInfo = this._infocard.querySelector('.path-info'); /** @type {HTMLDivElement} */ this._iconInfo = this._infocard.querySelector('.icon-info'); - /** @type {HTMLParagraphElement} */ + /** @type {HTMLSpanElement} */ this._typeInfo = this._infocard.querySelector('.type-info'); /** @@ -136,6 +148,12 @@ } class SymbolInfocard extends Infocard { + constructor(id) { + super(id); + /** @type {HTMLSpanElement} */ + this._flagsInfo = this._infocard.querySelector('.flags-info'); + } + /** * @param {SVGSVGElement} icon Icon to display */ @@ -144,6 +162,31 @@ super._setTypeContent(icon); this._iconInfo.style.backgroundColor = color; } + + /** + * Updates the DOM for the info card. + * @param {TreeNode} node + */ + _updateInfocard(node) { + super._updateInfocard(node); + this._flagsInfo.textContent = this._flagsString(node); + } + + /** + * Returns a string representing the flags in the node. + * @param {TreeNode} symbolNode + */ + _flagsString(symbolNode) { + if (!symbolNode.flags) { + return ''; + } + + const flagsString = Array.from(_FLAG_LABELS) + .filter(([flag]) => hasFlag(flag, symbolNode)) + .map(([, part]) => part) + .join(','); + return `{${flagsString}}`; + } } class ContainerInfocard extends Infocard { @@ -162,7 +205,6 @@ r: this._tableBody.querySelector('.rodata-info'), t: this._tableBody.querySelector('.text-info'), v: this._tableBody.querySelector('.vtable-info'), - '*': this._tableBody.querySelector('.gen-info'), x: this._tableBody.querySelector('.dexnon-info'), m: this._tableBody.querySelector('.dex-info'), p: this._tableBody.querySelector('.pak-info'), @@ -272,7 +314,7 @@ * @param {TreeNode} containerNode */ _updateInfocard(containerNode) { - const extraRows = {...this._infoRows}; + const extraRows = Object.assign({}, this._infoRows); const statsEntries = Object.entries(containerNode.childStats).sort( (a, b) => b[1].size - a[1].size );
diff --git a/tools/binary_size/libsupersize/static/infocard.css b/tools/binary_size/libsupersize/static/infocard.css index 86f139b..02d3d26 100644 --- a/tools/binary_size/libsupersize/static/infocard.css +++ b/tools/binary_size/libsupersize/static/infocard.css
@@ -78,7 +78,7 @@ .symbol-name-info { font-weight: 500; } -.type-info { +.type-info-container { grid-area: type; margin-bottom: 0; }
diff --git a/tools/binary_size/libsupersize/static/shared.js b/tools/binary_size/libsupersize/static/shared.js index 6892a57..4e0ac18 100644 --- a/tools/binary_size/libsupersize/static/shared.js +++ b/tools/binary_size/libsupersize/static/shared.js
@@ -23,6 +23,7 @@ * @prop {number} size Byte size of this node and its children. * @prop {string} type Type of this node. If this node has children, the string * may have a second character to denote the most common child. + * @prop {number} flags * @prop {{[type: string]: {size:number,count:number}}} childStats Stats about * this node's descendants, organized by symbol type. */ @@ -57,6 +58,20 @@ SIZE: /** @type {'b'} */ ('b'), TYPE: /** @type {'t'} */ ('t'), COUNT: /** @type {'u'} */ ('u'), + FLAGS: /** @type {'f'} */ ('f'), +}); + +/** Abberivated keys used by FileEntrys in the JSON data file. */ +const _FLAGS = Object.freeze({ + ANONYMOUS: 2 ** 0, + STARTUP: 2 ** 1, + UNLIKELY: 2 ** 2, + REL: 2 ** 3, + REL_LOCAL: 2 ** 4, + GENERATED_SOURCE: 2 ** 5, + CLONE: 2 ** 6, + HOT: 2 ** 7, + COVERAGE: 2 ** 8, }); /** @@ -69,8 +84,6 @@ KiB: 1024 ** 1, B: 1024 ** 0, }); -/** Set of all byte units */ -const _BYTE_UNITS_SET = new Set(Object.keys(_BYTE_UNITS)); /** * Special types used by containers, such as folders and files. @@ -83,13 +96,15 @@ }; const _CONTAINER_TYPE_SET = new Set(Object.values(_CONTAINER_TYPES)); +/** Type for a code/.text symbol */ +const _CODE_SYMBOL_TYPE = 't'; /** Type for a dex method symbol */ const _DEX_METHOD_SYMBOL_TYPE = 'm'; /** Type for an 'other' symbol */ const _OTHER_SYMBOL_TYPE = 'o'; /** Set of all known symbol types. Container types are not included. */ -const _SYMBOL_TYPE_SET = new Set('bdrtv*xmpP' + _OTHER_SYMBOL_TYPE); +const _SYMBOL_TYPE_SET = new Set('bdrtvxmpP' + _OTHER_SYMBOL_TYPE); /** Name used by a directory created to hold symbols with no name. */ const _NO_NAME = '(No path)'; @@ -133,9 +148,18 @@ function debounce(func, wait) { /** @type {number} */ let timeoutId; - function debounced (...args) { + function debounced(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func(...args), wait); - }; + } return /** @type {any} */ (debounced); } + +/** + * Returns tree if a symbol has a certain bit flag + * @param {number} flag Bit flag from `_FLAGS` + * @param {TreeNode} symbolNode + */ +function hasFlag(flag, symbolNode) { + return (symbolNode.flags & flag) === flag; +}
diff --git a/tools/binary_size/libsupersize/static/state.js b/tools/binary_size/libsupersize/static/state.js index f0f1abf..531c600 100644 --- a/tools/binary_size/libsupersize/static/state.js +++ b/tools/binary_size/libsupersize/static/state.js
@@ -68,44 +68,11 @@ const state = Object.freeze({ /** * Returns a string from the current query string state. - * Can optionally restrict valid values for the query. - * Values not present in the query will return null, or the default - * value if supplied. * @param {string} key - * @param {object} [options] - * @param {string} [options.default] Default to use if key is not present - * in the state - * @param {Set<string>} [options.valid] If provided, values must be in this - * set to be returned. Invalid values will return null or `defaultValue`. * @returns {string | null} */ - get(key, options = {}) { - const [val = null] = state.getAll(key, { - default: options.default ? [options.default] : null, - valid: options.valid, - }); - return val; - }, - /** - * Returns all string values for a key from the current query string state. - * Can optionally provide default values used if there are no values. - * @param {string} key - * @param {object} [options] - * @param {string[]} [options.default] Default to use if key is not present - * in the state. - * @param {Set<string>} [options.valid] If provided, values must be in this - * set to be returned. Invalid values will be omitted. - * @returns {string[]} - */ - getAll(key, options = {}) { - let vals = _filterParams.getAll(key); - if (options.valid != null) { - vals = vals.filter(val => options.valid.has(val)); - } - if (options.default != null && vals.length === 0) { - vals = options.default; - } - return vals; + get(key) { + return _filterParams.get(key); }, /** * Checks if a key is present in the query string state. @@ -140,7 +107,7 @@ }); // Update form inputs to reflect the state from URL. - for (const element of form.elements) { + for (const element of Array.from(form.elements)) { if (element.name) { const input = /** @type {HTMLInputElement} */ (element); const values = _filterParams.getAll(input.name); @@ -370,12 +337,15 @@ }; } else { const bytes = node.size; - const unit = state.get('byteunit', { - default: 'MiB', - valid: _BYTE_UNITS_SET, - }); + let unit = state.get('byteunit'); + let suffix = _BYTE_UNITS[unit]; + if (suffix == null) { + unit = 'MiB'; + suffix = _BYTE_UNITS.MiB; + } + // Format the bytes as a number with 2 digits after the decimal point - const text = (bytes / _BYTE_UNITS[unit]).toLocaleString(_LOCALE, { + const text = (bytes / suffix).toLocaleString(_LOCALE, { minimumFractionDigits: 2, maximumFractionDigits: 2, });
diff --git a/tools/binary_size/libsupersize/static/tree-ui.js b/tools/binary_size/libsupersize/static/tree-ui.js index 4ace63c..6720848 100644 --- a/tools/binary_size/libsupersize/static/tree-ui.js +++ b/tools/binary_size/libsupersize/static/tree-ui.js
@@ -24,6 +24,9 @@ const _treeTemplate = document.getElementById('treenode-container'); const _symbolTree = document.getElementById('symboltree'); + const _highlightRadio = document.getElementById('highlight-container'); + /** @type {HTMLSelectElement} */ + const _byteunitSelect = form.elements.namedItem('byteunit'); /** * @type {HTMLCollectionOf<HTMLAnchorElement | HTMLSpanElement>} @@ -45,12 +48,64 @@ const _uiNodeData = new WeakMap(); /** + * @type {{[mode:string]: (nameEl: HTMLSpanElement, node: TreeNode) => void}} + */ + const _highlightActions = { + hot(symbolName, symbolNode) { + if (hasFlag(_FLAGS.HOT, symbolNode)) { + symbolName.classList.add('highlight'); + } + }, + generated(symbolName, symbolNode) { + if (hasFlag(_FLAGS.GENERATED_SOURCE, symbolNode)) { + symbolName.classList.add('highlight'); + } + }, + coverage(symbolName, symbolNode) { + if (symbolNode.type === _CODE_SYMBOL_TYPE) { + if (hasFlag(_FLAGS.COVERAGE, symbolNode)) { + symbolName.classList.add('highlight-positive'); + } else { + symbolName.classList.add('highlight-negative'); + } + } + }, + reset(symbolName) { + symbolName.classList.remove('highlight'); + symbolName.classList.remove('highlight-positive'); + symbolName.classList.remove('highlight-negative'); + }, + }; + + /** + * Applies highlights to the tree element based on certain flags and state. + * @param {HTMLSpanElement} symbolNameElement + * @param {TreeNode} symbolNode + */ + function _highlightSymbolName(symbolNameElement, symbolNode) { + const isDexMethod = symbolNode.type === _DEX_METHOD_SYMBOL_TYPE; + if (isDexMethod && state.has('method_count')) { + const {count = 0} = symbolNode.childStats[_DEX_METHOD_SYMBOL_TYPE] || {}; + if (count < 0) { + symbolNameElement.classList.add('removed'); + } + } + + const hightlightFunc = _highlightActions[state.get('highlight')]; + _highlightActions.reset(symbolNameElement, symbolNode); + if (hightlightFunc) { + hightlightFunc(symbolNameElement, symbolNode); + } + } + + /** * Sets focus to a new tree element while updating the element that last had * focus. The tabindex property is used to avoid needing to tab through every * single tree item in the page to reach other areas. * @param {number | HTMLElement} el Index of tree node in `_liveNodeList` */ function _focusTreeElement(el) { + /** @type {HTMLElement} */ const lastFocused = document.activeElement; if (_uiNodeData.has(lastFocused)) { // Update DOM @@ -86,7 +141,9 @@ let data = _uiNodeData.get(link); if (data == null || data.children == null) { - const idPath = link.querySelector('.symbol-name').title; + /** @type {HTMLSpanElement} */ + const symbolName = link.querySelector('.symbol-name'); + const idPath = symbolName.title; data = await worker.openNode(idPath); _uiNodeData.set(link, data); } @@ -95,7 +152,9 @@ if (newElements.length === 1) { // Open the inner element if it only has a single child. // Ensures nodes like "java"->"com"->"google" are opened all at once. - newElements[0].querySelector('.node').click(); + /** @type {HTMLAnchorElement | HTMLSpanElement} */ + const link = newElements[0].querySelector('.node'); + link.click(); } const newElementsFragment = dom.createFragment(newElements); @@ -185,7 +244,9 @@ const groupList = link.parentElement.parentElement; if (groupList.getAttribute('role') === 'group') { event.preventDefault(); - _focusTreeElement(groupList.previousElementSibling); + /** @type {HTMLAnchorElement} */ + const parentLink = groupList.previousElementSibling; + _focusTreeElement(parentLink); } } } @@ -292,13 +353,7 @@ _ZERO_WIDTH_SPACE ); symbolName.title = data.idPath; - - if (state.has('method_count') && type === _DEX_METHOD_SYMBOL_TYPE) { - const {count = 0} = data.childStats[type] || {}; - if (count < 0) { - symbolName.classList.add('removed'); - } - } + _highlightSymbolName(symbolName, data); // Set the byte size and hover text _setSize(element.querySelector('.size'), data); @@ -312,7 +367,7 @@ } // When the `byteunit` state changes, update all .size elements in the page - form.elements.namedItem('byteunit').addEventListener('change', event => { + _byteunitSelect.addEventListener('change', event => { event.stopPropagation(); state.set(event.currentTarget.name, event.currentTarget.value); // Update existing size elements with the new unit @@ -321,6 +376,19 @@ if (data) _setSize(sizeElement, data); } }); + _highlightRadio.addEventListener('change', event => { + event.stopPropagation(); + state.set(event.target.name, event.target.value); + // Update existing symbol elements + for (const link of _liveNodeList) { + const data = _uiNodeData.get(link); + if (data.children && data.children.length === 0) { + /** @type {HTMLSpanElement} */ + const symbolName = link.querySelector('.symbol-name'); + _highlightSymbolName(symbolName, data); + } + } + }); _symbolTree.addEventListener('keydown', _handleKeyNavigation); _symbolTree.addEventListener('focusin', event => { @@ -337,7 +405,7 @@ } }); - return newTreeElement + return newTreeElement; })(); {
diff --git a/tools/binary_size/libsupersize/static/tree-worker.js b/tools/binary_size/libsupersize/static/tree-worker.js index 0597776..5c9eef2 100644 --- a/tools/binary_size/libsupersize/static/tree-worker.js +++ b/tools/binary_size/libsupersize/static/tree-worker.js
@@ -24,6 +24,7 @@ * @prop {string} t Single character string to indicate the symbol type. * @prop {number} [u] Count value indicating how many symbols this entry * represents. Negative value when removed in a diff. + * @prop {number} [f] Bit flags, defaults to 0. */ /** * @typedef {object} FileEntry JSON object representing a single file and its @@ -82,7 +83,14 @@ * @returns {TreeNode} */ function createNode(options) { - const {idPath, type, shortNameIndex, size = 0, childStats = {}} = options; + const { + idPath, + type, + shortNameIndex, + size = 0, + flags = 0, + childStats = {}, + } = options; return { children: [], parent: null, @@ -91,6 +99,7 @@ shortNameIndex, size, type, + flags, }; } @@ -143,13 +152,14 @@ const additionalSize = node.size; const additionalStats = Object.entries(node.childStats); + const additionalFlags = node.flags; // Update the size and childStats of all ancestors while (node.parent != null) { const {parent} = node; const [containerType, lastBiggestType] = parent.type; let {size: lastBiggestSize = 0} = - parent.childStats[lastBiggestType] || {}; + parent.childStats[lastBiggestType] || {}; for (const [type, stat] of additionalStats) { const parentStat = parent.childStats[type] || {size: 0, count: 0}; @@ -165,6 +175,7 @@ } parent.size += additionalSize; + parent.flags |= additionalFlags; node = parent; } } @@ -257,15 +268,16 @@ // If there is 1 child, include it so the UI doesn't need to make a // roundtrip in order to expand the chain. children = node.children - .map(n => TreeBuilder.formatNode(n, childDepth)) - .sort(_compareFunc); + .map(n => TreeBuilder.formatNode(n, childDepth)) + .sort(_compareFunc); } - return TreeBuilder._joinDexMethodClasses({ - ...node, - children, - parent: null, - }); + return TreeBuilder._joinDexMethodClasses( + Object.assign({}, node, { + children, + parent: null, + }) + ); } /** @@ -344,7 +356,8 @@ idPath: `${idPath}:${symbol[_KEYS.SYMBOL_NAME]}`, shortNameIndex: idPath.length + 1, size, - type: symbol[_KEYS.TYPE], + type, + flags: symbol[_KEYS.FLAGS] || 0, childStats: {[type]: {size, count}}, }); @@ -548,6 +561,7 @@ const groupBy = params.get('group_by') || 'source_path'; const methodCountMode = params.has('method_count'); + const filterGeneratedFiles = params.has('generated_filter'); let minSymbolSize = Number(params.get('min_size')); if (Number.isNaN(minSymbolSize)) { @@ -569,19 +583,28 @@ } } - /** @type {Array<(symbolNode: TreeNode) => boolean>} */ + /** + * @type {Array<(symbolNode: TreeNode) => boolean>} List of functions that + * check each symbol. If any returns false, the symbol will not be used. + */ const filters = []; - /** Ensure symbol size is past the minimum */ + // Ensure symbol size is past the minimum if (minSymbolSize > 0) { filters.push(s => Math.abs(s.size) >= minSymbolSize); } - /** Ensure the symbol size wasn't filtered out */ + // Ensure the symbol size wasn't filtered out if (typeFilter.size < _SYMBOL_TYPE_SET.size) { filters.push(s => typeFilter.has(s.type)); } + // Only show generated files + if (filterGeneratedFiles) { + filters.push(s => hasFlag(_FLAGS.GENERATED_SOURCE, s)); + } + + // Search symbol names using regex if (includeRegex) { try { const regex = new RegExp(includeRegex); @@ -692,7 +715,7 @@ const currentTime = Date.now(); if (currentTime - lastBatchSent > 500) { postToUi(); - await Promise.resolve(); // Pause loop to check for worker messages + await Promise.resolve(); // Pause loop to check for worker messages lastBatchSent = currentTime; } }
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 14de8d2..933cca3 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -438,6 +438,7 @@ }, 'chromium.webrtc': { + 'Android Builder': 'android_debug_static_bot_arm64', 'Linux Builder': 'release_bot_chrome_with_codecs', 'Mac Builder': 'release_bot_chrome_with_codecs', 'Win Builder': 'release_bot_x86_minimal_symbols_no_com_init_hooks_with_codecs',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 57ab8ab2..8228f0f 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -504,6 +504,17 @@ <int value="2" label="Failed (missing product details)"/> </enum> +<enum name="AddIceCandidateResult"> + <int value="0" label="Success"/> + <int value="1" label="Closed"/> + <int value="2" label="No remote description"/> + <int value="3" label="Null candidate"/> + <int value="4" label="Candidate not valid"/> + <int value="5" label="PeerConnection not ready"/> + <int value="6" label="Failed in addition"/> + <int value="7" label="Failed - not usable"/> +</enum> + <enum name="AddressFamily"> <int value="0" label="Unspecified"/> <int value="1" label="IPv4"/> @@ -8226,6 +8237,7 @@ <int value="2" label="kUnexpectedTime"/> <int value="3" label="kDatabaseError"/> <int value="4" label="kUploadFailed"/> + <int value="5" label="kPrepareForUploadFailed"/> </enum> <enum name="CrashpadWinExceptionCodes"> @@ -19426,6 +19438,7 @@ <int value="2513" label="V8RTCPeerConnection_AddTransceiver_Method"/> <int value="2514" label="V8RTCRtpTransceiver_Direction_AttributeGetter"/> <int value="2515" label="V8RTCRtpTransceiver_Direction_AttributeSetter"/> + <int value="2516" label="HTMLLinkElementDisabledByParser"/> </enum> <enum name="FeedbackSource">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 29edf4c3..c28e1cd 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -112764,6 +112764,15 @@ </summary> </histogram> +<histogram name="WebRTC.PeerConnection.AddCandidate" + enum="AddIceCandidateResult" expires_after="M72"> + <owner>hta@chromium.org</owner> + <summary> + Outcomes of adding ICE candidates to a PeerConnection. Used to check the + theory that failures in candidate addition are ignored by applications. + </summary> +</histogram> + <histogram name="WebRTC.PeerConnection.CandidatePairType" enum="IceCandidatePairTypes"> <owner>guoweis@chromium.org</owner>
diff --git a/tools/perf/core/oauth_api.py b/tools/perf/core/oauth_api.py deleted file mode 100644 index 88869e6..0000000 --- a/tools/perf/core/oauth_api.py +++ /dev/null
@@ -1,38 +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. - -"""API for generating OAuth2 access tokens from service account -keys predeployed to Chrome Ops bots via Puppet. -""" - -import contextlib -import os -import subprocess -import tempfile - - -@contextlib.contextmanager -def with_access_token( - service_account_json, prefix, token_expiration_in_minutes): - """Yields an access token for the service account. - - Args: - service_account_json: The path to the service account JSON file. - prefix: the prefix of the token file - token_expiration_in_minutes: the integer expiration time of the token - """ - fd, path = tempfile.mkstemp(suffix='.json', prefix=prefix) - try: - args = ['luci-auth', 'token'] - if service_account_json: - args += ['-service-account-json', service_account_json] - args += ['-lifetime', '%im' % token_expiration_in_minutes] - subprocess.check_call(args, stdout=fd) - os.close(fd) - fd = None - yield path - finally: - if fd is not None: - os.close(fd) - os.remove(path)
diff --git a/tools/perf/core/results_dashboard.py b/tools/perf/core/results_dashboard.py index 2d2d9a9..984882e2 100755 --- a/tools/perf/core/results_dashboard.py +++ b/tools/perf/core/results_dashboard.py
@@ -34,10 +34,7 @@ # The paths in the results dashboard URLs for sending results. SEND_RESULTS_PATH = '/add_point' SEND_HISTOGRAMS_PATH = '/add_histograms' - - -ERROR_NO_OAUTH_TOKEN = ( - 'No oauth token provided, cannot upload HistogramSet. Discarding.') +DEFAULT_TOKEN_TIMEOUT_IN_MINUTES = 30 class SendResultException(Exception): @@ -52,7 +49,22 @@ pass -def SendResults(data, url, send_as_histograms=False, oauth_token=None, +def LuciAuthTokenGeneratorCallback( + service_account_file, token_expiration_in_minutes): + args = ['luci-auth', 'token', + '-service-account-json', service_account_file, + '-lifetime', '%im' % token_expiration_in_minutes] + p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if p.wait() == 0: + return p.stdout.read() + else: + raise RuntimeError( + 'Error generating authentication token.\nStdout: %s\nStder:%s' % + (p.stdout.read(), p.stderr.read())) + + +def SendResults(data, url, send_as_histograms=False, service_account_file=None, + token_generator_callback=LuciAuthTokenGeneratorCallback, num_retries=3): """Sends results to the Chrome Performance Dashboard. @@ -62,18 +74,31 @@ data: The data to try to send. Must be JSON-serializable. url: Performance Dashboard URL (including schema). send_as_histograms: True if result is to be sent to /add_histograms. - oauth_token: string; used for flushing oauth uploads from cache. Note that - client is responsible for making sure that the oauth_token doesn't expire - when using this API. + service_account_file: string; path to service account file which is used + for authenticating when upload data to perf dashboard. + token_generator_callback: a callback for generating the authentication token + to upload to perf dashboard. + This callback takes two parameters + (service_account_file, token_expiration_in_minutes) and returns the token + string. + If |token_generator_callback| is not specified, it's default to + LuciAuthTokenGeneratorCallback. num_retries: Number of times to retry uploading to the perf dashboard upon recoverable error. """ start = time.time() + if send_as_histograms and not service_account_file: + raise ValueError( + 'Must set a valid service_account_file for uploading histogram set ' + 'data') + # Send all the results from this run and the previous cache to the # dashboard. errors, all_data_uploaded = _SendResultsToDashboard( - data, url, oauth_token, is_histogramset=send_as_histograms, + data, url, is_histogramset=send_as_histograms, + service_account_file=service_account_file, + token_generator_callback=token_generator_callback, num_retries=num_retries) print 'Time spent sending results to %s: %s' % (url, time.time() - start) @@ -85,15 +110,12 @@ def _SendResultsToDashboard( - dashboard_data, url, oauth_token, is_histogramset, num_retries): + dashboard_data, url, is_histogramset, service_account_file, + token_generator_callback, num_retries): """Tries to send perf dashboard data to |url|. Args: - perf_results_file_path: A file name. - url: The instance URL to which to post results. - oauth_token: An oauth token to use for histogram uploads. Might be None. - num_retries: Number of time to retry uploading to the perf dashboard upon - recoverable error. + See arguments in SendResults method above. Returns: A tuple (errors, all_data_uploaded), whereas: @@ -107,26 +129,26 @@ data_type = ('histogram' if is_histogramset else 'chartjson') + dashboard_data_str = json.dumps(dashboard_data) + for i in xrange(1, num_retries + 1): try: print 'Sending %s result to dashboard (attempt %i out of %i).' % ( data_type, i, num_retries) if is_histogramset: - # TODO(eakuefner): Remove this discard logic once all bots use - # histograms. - if oauth_token is None: - raise SendResultsFatalException(ERROR_NO_OAUTH_TOKEN) - - _SendHistogramJson(url, json.dumps(dashboard_data), oauth_token) + oauth_token = token_generator_callback( + service_account_file, DEFAULT_TOKEN_TIMEOUT_IN_MINUTES) + _SendHistogramJson(url, dashboard_data_str, oauth_token) else: - _SendResultsJson(url, json.dumps(dashboard_data)) + # TODO(eakuefner): Remove this logic once all bots use histograms. + _SendResultsJson(url, dashboard_data_str) all_data_uploaded = True break except SendResultsRetryException as e: error = 'Error while uploading %s data: %s' % (data_type, str(e)) errors.append(error) except SendResultsFatalException as e: - error = 'Error uploading %s data: %s' % (data_type, str(e)) + error = 'Fatal error while uploading %s data: %s' % (data_type, str(e)) errors.append(error) break except Exception: @@ -477,10 +499,10 @@ # A 500 is presented on an exception on the dashboard side, timeout, # exception, etc. The dashboard can also send back 400 and 403, we could # recover from 403 (auth error), but 400 is generally malformed data. - if response.status == 403: - raise SendResultsRetryException(traceback.format_exc()) - - if response.status != 200: + if response.status in (403, 500): + raise SendResultsRetryException('HTTP Response %d: %s' % ( + response.status, response.reason)) + elif response.status != 200: raise SendResultsFatalException('HTTP Response %d: %s' % ( response.status, response.reason)) except httplib2.HttpLib2Error:
diff --git a/tools/perf/core/results_dashboard_unittest.py b/tools/perf/core/results_dashboard_unittest.py index 10213d7..a242a87 100644 --- a/tools/perf/core/results_dashboard_unittest.py +++ b/tools/perf/core/results_dashboard_unittest.py
@@ -11,34 +11,38 @@ class ResultsDashboardTest(unittest.TestCase): def setUp(self): - self.fake_oath = 'fake-oath' + self.fake_service = '/foo/bar/kingsman-service-account' + self.dummy_token_generator = lambda service_file, timeout: 'Arthur-Merlin' self.perf_data = {'foo': 1, 'bar': 2} self.dashboard_url = 'https://chromeperf.appspot.com' def testRetryForSendResultRetryException(self): - def raise_retry_exception(url, histogramset_json, oauth_token): - del url, histogramset_json, oauth_token # unused + def raise_retry_exception(url, histogramset_json, service_account_file): + del url, histogramset_json, service_account_file # unused raise results_dashboard.SendResultsRetryException('Should retry') with mock.patch('core.results_dashboard._SendHistogramJson', side_effect=raise_retry_exception) as m: upload_result = results_dashboard.SendResults( self.perf_data, self.dashboard_url, send_as_histograms=True, - oauth_token=self.fake_oath, num_retries=5) + service_account_file=self.fake_service, + token_generator_callback=self.dummy_token_generator, num_retries=5) self.assertFalse(upload_result) self.assertEqual(m.call_count, 5) def testNoRetryForSendResultFatalException(self): - def raise_retry_exception(url, histogramset_json, oauth_token): - del url, histogramset_json, oauth_token # unused + def raise_retry_exception(url, histogramset_json, service_account_file): + del url, histogramset_json, service_account_file # unused raise results_dashboard.SendResultsFatalException('Do not retry') with mock.patch('core.results_dashboard._SendHistogramJson', side_effect=raise_retry_exception) as m: upload_result = results_dashboard.SendResults( self.perf_data, self.dashboard_url, send_as_histograms=True, - oauth_token=self.fake_oath, num_retries=5) + service_account_file=self.fake_service, + token_generator_callback=self.dummy_token_generator, + num_retries=5) self.assertFalse(upload_result) self.assertEqual(m.call_count, 1) @@ -46,15 +50,17 @@ with mock.patch('core.results_dashboard._SendHistogramJson') as m: upload_result = results_dashboard.SendResults( self.perf_data, self.dashboard_url, send_as_histograms=True, - oauth_token=self.fake_oath, num_retries=5) + service_account_file=self.fake_service, + token_generator_callback=self.dummy_token_generator, + num_retries=5) self.assertTrue(upload_result) self.assertEqual(m.call_count, 1) def testNoRetryAfterSucessfulSendResult(self): counter = [0] def raise_retry_exception_first_two_times( - url, histogramset_json, oauth_token): - del url, histogramset_json, oauth_token # unused + url, histogramset_json, service_account_file): + del url, histogramset_json, service_account_file # unused counter[0] += 1 if counter[0] <= 2: raise results_dashboard.SendResultsRetryException('Please retry') @@ -63,6 +69,8 @@ side_effect=raise_retry_exception_first_two_times) as m: upload_result = results_dashboard.SendResults( self.perf_data, self.dashboard_url, send_as_histograms=True, - oauth_token=self.fake_oath, num_retries=5) + service_account_file=self.fake_service, + token_generator_callback=self.dummy_token_generator, + num_retries=5) self.assertTrue(upload_result) self.assertEqual(m.call_count, 3)
diff --git a/tools/perf/core/upload_results_to_perf_dashboard.py b/tools/perf/core/upload_results_to_perf_dashboard.py index 6133c8d..68e1bbd5 100755 --- a/tools/perf/core/upload_results_to_perf_dashboard.py +++ b/tools/perf/core/upload_results_to_perf_dashboard.py
@@ -101,7 +101,7 @@ parser.add_option('--git-revision') parser.add_option('--output-json-dashboard-url') parser.add_option('--send-as-histograms', action='store_true') - parser.add_option('--oauth-token-file') + parser.add_option('--service-account-file') return parser @@ -115,11 +115,7 @@ if not options.configuration_name or not options.results_url: parser.error('configuration_name and results_url are required.') - if options.oauth_token_file: - with open(options.oauth_token_file) as f: - oauth_token = f.readline() - else: - oauth_token = None + service_account_file = options.service_account_file or None if not options.perf_dashboard_machine_group: print 'Error: Invalid perf dashboard machine group' @@ -148,7 +144,7 @@ dashboard_json, options.results_url, send_as_histograms=options.send_as_histograms, - oauth_token=oauth_token): + service_account_file=service_account_file): return 1 else: # The upload didn't fail since there was no data to upload.
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py index 380e4970..3d279c3 100755 --- a/tools/perf/process_perf_results.py +++ b/tools/perf/process_perf_results.py
@@ -16,7 +16,6 @@ import time import uuid -from core import oauth_api from core import path_util from core import upload_results_to_perf_dashboard from core import results_merger @@ -64,7 +63,7 @@ def _upload_perf_results(json_to_upload, name, configuration_name, - build_properties, oauth_file, output_json_file): + build_properties, service_account_file, output_json_file): """Upload the contents of result JSON(s) to the perf dashboard.""" args= [ '--buildername', build_properties['buildername'], @@ -76,7 +75,7 @@ '--got-revision-cp', build_properties['got_revision_cp'], '--got-v8-revision', build_properties['got_v8_revision'], '--got-webrtc-revision', build_properties['got_webrtc_revision'], - '--oauth-token-file', oauth_file, + '--service-account-file', service_account_file, '--output-json-file', output_json_file, '--perf-dashboard-machine-group', _GetMachineGroup(build_properties) ] @@ -350,20 +349,15 @@ results_filename = join(directories[0], 'perf_results.json') print 'Uploading perf results from %s benchmark' % benchmark_name - # We generate an oauth token for every benchmark upload in the event - # the token could time out, see crbug.com/854162 - with oauth_api.with_access_token( - service_account_file, ('%s_tok' % benchmark_name), - token_expiration_in_minutes=30) as oauth_file: - with open(output_json_file, 'w') as oj: - upload_fail = _upload_perf_results( - results_filename, - benchmark_name, configuration_name, build_properties, - oauth_file, oj) - upload_end_time = time.time() - print_duration(('%s upload time' % (benchmark_name)), - upload_begin_time, upload_end_time) - return (benchmark_name, upload_fail) + with open(output_json_file, 'w') as oj: + upload_fail = _upload_perf_results( + results_filename, + benchmark_name, configuration_name, build_properties, + service_account_file, oj) + upload_end_time = time.time() + print_duration(('%s upload time' % (benchmark_name)), + upload_begin_time, upload_end_time) + return (benchmark_name, upload_fail) finally: shutil.rmtree(tmpfile_dir)
diff --git a/tools/perf/process_perf_results_unittest.py b/tools/perf/process_perf_results_unittest.py index 8aaeb50..e4a74a841 100755 --- a/tools/perf/process_perf_results_unittest.py +++ b/tools/perf/process_perf_results_unittest.py
@@ -8,7 +8,6 @@ import sys import tempfile import json -import contextlib import unittest from core import path_util @@ -44,35 +43,22 @@ self.task_output_dir = os.path.join( os.path.dirname(__file__), 'testdata', 'task_output_dir') - @contextlib.contextmanager - def mocked_with_access_token(service_account_json, append): - del service_account_json # unused - test_token_file = os.path.join(self.test_dir, 'token-%s' % append) - with open(test_token_file, 'w') as f: - f.write('1234') - yield test_token_file - - m1 = mock.patch('process_perf_results.oauth_api.with_access_token', - side_effect=mocked_with_access_token) + m1 = mock.patch( + 'process_perf_results.logdog_helper.text', + return_value = 'http://foo.link') m1.start() self.addCleanup(m1.stop) m2 = mock.patch( - 'process_perf_results.logdog_helper.text', - return_value = 'http://foo.link') + 'process_perf_results.logdog_helper.open_text', + return_value=_FakeLogdogStream()) m2.start() self.addCleanup(m2.stop) - m3 = mock.patch( - 'process_perf_results.logdog_helper.open_text', - return_value=_FakeLogdogStream()) + m3 = mock.patch('core.results_dashboard.SendResults') m3.start() self.addCleanup(m3.stop) - m4 = mock.patch('core.results_dashboard.SendResults') - m4.start() - self.addCleanup(m4.stop) - def tearDown(self): shutil.rmtree(self.test_dir)
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc index b281f47..735e150 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -6,7 +6,12 @@ #include <stdint.h> +#include <memory> +#include <string> +#include <utility> + #include "base/command_line.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "ui/accessibility/ax_action_data.h" @@ -306,7 +311,13 @@ static AtkAttributeSet* ax_platform_node_auralinux_get_attributes( AtkObject* atk_object) { - return NULL; + + ui::AXPlatformNodeAuraLinux* obj = + AtkObjectToAXPlatformNodeAuraLinux(atk_object); + if (!obj) + return nullptr; + + return obj->GetAtkAttributes(); } static AtkRole ax_platform_node_auralinux_get_role(AtkObject* atk_object) { @@ -973,9 +984,13 @@ case ax::mojom::Role::kAnnotation: return ATK_ROLE_PANEL; case ax::mojom::Role::kApplication: - // Don't use ATK_ROLE_APPLICATION, which is for top level app windows, - // not ARIA applications. - return ATK_ROLE_EMBEDDED; + // Only use ATK_ROLE_APPLICATION for elements with no parent, since it + // is only for top level app windows and not ARIA applications. + if (!GetParent()) { + return ATK_ROLE_APPLICATION; + } else { + return ATK_ROLE_EMBEDDED; + } case ax::mojom::Role::kArticle: return ATK_ROLE_ARTICLE; case ax::mojom::Role::kAudio: @@ -1252,7 +1267,6 @@ .empty() || IsFocusedInputWithSuggestions()) { return ATK_ROLE_AUTOCOMPLETE; - ; } return ATK_ROLE_ENTRY; case ax::mojom::Role::kTextFieldWithComboBox: @@ -1346,8 +1360,8 @@ atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSED); } -void AXPlatformNodeAuraLinux::GetAtkRelations(AtkRelationSet* atk_relation_set) -{ +void AXPlatformNodeAuraLinux::GetAtkRelations( + AtkRelationSet* atk_relation_set) { } AXPlatformNodeAuraLinux::AXPlatformNodeAuraLinux() @@ -1533,6 +1547,15 @@ ATK_AURALINUX_RETURN_STRING(base::UTF16ToUTF8(action_verb)); } +AtkAttributeSet* AXPlatformNodeAuraLinux::GetAtkAttributes() const { + AtkAttributeSet* atk_attributes = nullptr; + + atk_attributes = AddIntAttributeToAtkAttributeSet( + atk_attributes, ax::mojom::IntAttribute::kHierarchicalLevel, "level"); + + return atk_attributes; +} + // AtkDocumentHelpers const gchar* AXPlatformNodeAuraLinux::GetDocumentAttributeValue( @@ -1549,6 +1572,17 @@ return nullptr; } +static AtkAttributeSet* PrependAtkAttributeToAtkAttributeSet( + AtkAttributeSet* attribute_set, + const char* name, + const char* value) { + AtkAttribute* attribute = + static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute))); + attribute->name = g_strdup(name); + attribute->value = g_strdup(value); + return g_slist_prepend(attribute_set, attribute); +} + AtkAttributeSet* AXPlatformNodeAuraLinux::GetDocumentAttributes() const { AtkAttributeSet* attribute_set = nullptr; const gchar* doc_attributes[] = {"DocType", "MimeType", "Title", "URI"}; @@ -1557,11 +1591,8 @@ for (unsigned i = 0; i < G_N_ELEMENTS(doc_attributes); i++) { value = GetDocumentAttributeValue(doc_attributes[i]); if (value) { - AtkAttribute* attribute = - static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute))); - attribute->name = g_strdup(doc_attributes[i]); - attribute->value = g_strdup(value); - attribute_set = g_slist_prepend(attribute_set, attribute); + attribute_set = PrependAtkAttributeToAtkAttributeSet( + attribute_set, doc_attributes[i], value); } } @@ -1601,4 +1632,17 @@ } } +AtkAttributeSet* AXPlatformNodeAuraLinux::AddIntAttributeToAtkAttributeSet( + AtkAttributeSet* attributes, + ax::mojom::IntAttribute attribute, + const char* atk_attribute) const { + int value; + if (GetIntAttribute(attribute, &value)) { + attributes = PrependAtkAttributeToAtkAttributeSet( + attributes, atk_attribute, base::IntToString(value).c_str()); + } + + return attributes; +} + } // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h index e0c31e92..e34398c 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.h +++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -2,11 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_ACCESSIBILITY_AX_PLATFORM_NODE_AURALINUX_H_ -#define UI_ACCESSIBILITY_AX_PLATFORM_NODE_AURALINUX_H_ +#ifndef UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_AURALINUX_H_ +#define UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_AURALINUX_H_ #include <atk/atk.h> +#include <string> + #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "ui/accessibility/ax_export.h" @@ -57,6 +59,7 @@ bool GrabFocus(); bool DoDefaultAction(); const gchar* GetDefaultActionName(); + AtkAttributeSet* GetAtkAttributes() const; void SetExtentsRelativeToAtkCoordinateType( gint* x, gint* y, gint* width, gint* height, @@ -71,6 +74,10 @@ // Misc helpers void GetFloatAttributeInGValue(ax::mojom::FloatAttribute attr, GValue* value); + AtkAttributeSet* AddIntAttributeToAtkAttributeSet( + AtkAttributeSet* attributes, + ax::mojom::IntAttribute attribute, + const char* atk_attribute) const; // Event helpers void OnFocused(); @@ -124,4 +131,4 @@ } // namespace ui -#endif // UI_ACCESSIBILITY_AX_PLATFORM_NODE_AURALINUX_H_ +#endif // UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_AURALINUX_H_
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc index b9714a2b..eb4fd62 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -35,6 +35,44 @@ AtkObject* GetRootAtkObject() { return AtkObjectFromNode(GetRootNode()); } }; +static void EnsureAtkObjectHasAttributeWithValue( + AtkObject* atk_object, + const gchar* attribute_name, + const gchar* attribute_value) { + AtkAttributeSet* attributes = atk_object_get_attributes(atk_object); + bool saw_attribute = false; + + AtkAttributeSet* current = attributes; + while (current) { + AtkAttribute* attribute = static_cast<AtkAttribute*>(current->data); + + if (0 == strcmp(attribute_name, attribute->name)) { + // Ensure that we only see this attribute once. + ASSERT_FALSE(saw_attribute); + + EXPECT_STREQ(attribute_value, attribute->value); + saw_attribute = true; + } + + current = current->next; + } + + ASSERT_TRUE(saw_attribute); + atk_attribute_set_free(attributes); +} + +static void EnsureAtkObjectDoesNotHaveAttribute( + AtkObject* atk_object, + const gchar* attribute_name) { + AtkAttributeSet* attributes = atk_object_get_attributes(atk_object); + AtkAttributeSet* current = attributes; + while (current) { + AtkAttribute* attribute = static_cast<AtkAttribute*>(current->data); + ASSERT_NE(0, strcmp(attribute_name, attribute->name)); + } + atk_attribute_set_free(attributes); +} + // // AtkObject tests // @@ -105,6 +143,7 @@ AXNodeData root; root.id = 1; root.child_ids.push_back(2); + root.role = ax::mojom::Role::kApplication; AXNodeData child; child.id = 2; @@ -112,6 +151,12 @@ Init(root, child); AXNode* child_node = GetRootNode()->children()[0]; + AtkObject* root_obj(AtkObjectFromNode(GetRootNode())); + ASSERT_TRUE(ATK_IS_OBJECT(root_obj)); + g_object_ref(root_obj); + EXPECT_EQ(ATK_ROLE_APPLICATION, atk_object_get_role(root_obj)); + g_object_unref(root_obj); + child.role = ax::mojom::Role::kAlert; child_node->SetData(child); AtkObject* child_obj(AtkObjectFromNode(child_node)); @@ -135,6 +180,14 @@ g_object_ref(child_obj); EXPECT_EQ(ATK_ROLE_CANVAS, atk_object_get_role(child_obj)); g_object_unref(child_obj); + + child.role = ax::mojom::Role::kApplication; + child_node->SetData(child); + child_obj = AtkObjectFromNode(child_node); + ASSERT_TRUE(ATK_IS_OBJECT(child_obj)); + g_object_ref(child_obj); + EXPECT_EQ(ATK_ROLE_EMBEDDED, atk_object_get_role(child_obj)); + g_object_unref(child_obj); } TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectState) { @@ -244,6 +297,39 @@ g_object_unref(root_obj); } +TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectAttributes) { + AXNodeData root_data; + root_data.id = 1; + + Init(root_data); + + AXNode* root_node = GetRootNode(); + AtkObject* root_atk_object(AtkObjectFromNode(root_node)); + ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object)); + g_object_ref(root_atk_object); + EnsureAtkObjectDoesNotHaveAttribute(root_atk_object, "level"); + + root_data = AXNodeData(); + root_data.id = 1; + root_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 1); + root_node->SetData(root_data); + EnsureAtkObjectHasAttributeWithValue(root_atk_object, "level", "1"); + + root_data = AXNodeData(); + root_data.id = 1; + root_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 2); + root_node->SetData(root_data); + EnsureAtkObjectHasAttributeWithValue(root_atk_object, "level", "2"); + + root_data = AXNodeData(); + root_data.id = 1; + root_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 34); + root_node->SetData(root_data); + EnsureAtkObjectHasAttributeWithValue(root_atk_object, "level", "34"); + + g_object_unref(root_atk_object); +} + // // AtkComponent tests //
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index fe0f3230..4e471cb 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -433,16 +433,17 @@ return host_->IsVisible(); } -bool Compositor::ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset) { +bool Compositor::ScrollLayerTo(cc::ElementId element_id, + const gfx::ScrollOffset& offset) { auto input_handler = host_->GetInputHandler(); - return input_handler && input_handler->ScrollLayerTo(layer_id, offset); + return input_handler && input_handler->ScrollLayerTo(element_id, offset); } -bool Compositor::GetScrollOffsetForLayer(int layer_id, +bool Compositor::GetScrollOffsetForLayer(cc::ElementId element_id, gfx::ScrollOffset* offset) const { auto input_handler = host_->GetInputHandler(); return input_handler && - input_handler->GetScrollOffsetForLayer(layer_id, offset); + input_handler->GetScrollOffsetForLayer(element_id, offset); } void Compositor::SetAuthoritativeVSyncInterval(
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index fccba71..b3c7e5f 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -18,6 +18,7 @@ #include "base/single_thread_task_runner.h" #include "base/time/time.h" #include "build/build_config.h" +#include "cc/trees/element_id.h" #include "cc/trees/layer_tree_host_client.h" #include "cc/trees/layer_tree_host_single_thread_client.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" @@ -299,8 +300,9 @@ // Gets or sets the scroll offset for the given layer in step with the // cc::InputHandler. Returns true if the layer is active on the impl side. - bool GetScrollOffsetForLayer(int layer_id, gfx::ScrollOffset* offset) const; - bool ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset); + bool GetScrollOffsetForLayer(cc::ElementId element_id, + gfx::ScrollOffset* offset) const; + bool ScrollLayerTo(cc::ElementId element_id, const gfx::ScrollOffset& offset); // The "authoritative" vsync interval, if provided, will override interval // reported from 3D context. This is typically the value reported by a more
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc index 64fba7f..9a6e9b7 100644 --- a/ui/compositor/layer.cc +++ b/ui/compositor/layer.cc
@@ -983,7 +983,7 @@ const Compositor* compositor = GetCompositor(); gfx::ScrollOffset offset; if (compositor && - compositor->GetScrollOffsetForLayer(cc_layer_->id(), &offset)) + compositor->GetScrollOffsetForLayer(cc_layer_->element_id(), &offset)) return offset; return cc_layer_->CurrentScrollOffset(); } @@ -991,7 +991,7 @@ void Layer::SetScrollOffset(const gfx::ScrollOffset& offset) { Compositor* compositor = GetCompositor(); bool scrolled_on_impl_side = - compositor && compositor->ScrollLayerTo(cc_layer_->id(), offset); + compositor && compositor->ScrollLayerTo(cc_layer_->element_id(), offset); if (!scrolled_on_impl_side) cc_layer_->SetScrollOffset(offset);
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc index 25117194..0b54ce2 100644 --- a/ui/events/blink/input_handler_proxy_unittest.cc +++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -124,11 +124,12 @@ cc::ScrollElasticityHelper* CreateScrollElasticityHelper() override { return NULL; } - bool GetScrollOffsetForLayer(int layer_id, + bool GetScrollOffsetForLayer(cc::ElementId element_id, gfx::ScrollOffset* offset) override { return false; } - bool ScrollLayerTo(int layer_id, const gfx::ScrollOffset& offset) override { + bool ScrollLayerTo(cc::ElementId element_id, + const gfx::ScrollOffset& offset) override { return false; }
diff --git a/ui/gfx/OWNERS b/ui/gfx/OWNERS index 8fb8afb..128cf4c 100644 --- a/ui/gfx/OWNERS +++ b/ui/gfx/OWNERS
@@ -22,6 +22,7 @@ # Skia geometry helpers. per-file skia_util*=danakj@chromium.org +per-file skia_paint_util*=danakj@chromium.org # GPU memory buffer and GpuFence interfaces. per-file gpu_fence*=reveman@chromium.org
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc index 50fce2dd..530e809 100644 --- a/ui/views/bubble/bubble_frame_view.cc +++ b/ui/views/bubble/bubble_frame_view.cc
@@ -272,6 +272,7 @@ !delegate->GetWindowTitle().empty()); default_title_->SetText(delegate->GetWindowTitle()); } // custom_title_'s updates are handled by its creator. + Layout(); } void BubbleFrameView::SizeConstraintsChanged() {}
diff --git a/ui/views/controls/menu/menu_config_mac.mm b/ui/views/controls/menu/menu_config_mac.mm index b838f66..9093926 100644 --- a/ui/views/controls/menu/menu_config_mac.mm +++ b/ui/views/controls/menu/menu_config_mac.mm
@@ -16,18 +16,18 @@ // images linked from that bug. config->menu_horizontal_border_size = 0; config->submenu_horizontal_inset = 0; - config->minimum_text_item_height = 32; - config->minimum_container_item_height = 48; + config->minimum_text_item_height = 28; + config->minimum_container_item_height = 40; config->minimum_menu_width = 320; config->label_to_arrow_padding = 0; config->arrow_to_edge_padding = 16; config->check_width = 16; config->check_height = 16; config->arrow_width = 8; - config->separator_height = 17; - config->separator_lower_height = 9; - config->separator_upper_height = 9; - config->separator_spacing_height = 9; + config->separator_height = 9; + config->separator_lower_height = 4; + config->separator_upper_height = 4; + config->separator_spacing_height = 5; config->separator_thickness = 1; config->align_arrow_and_shortcut = true; config->use_outer_border = false;
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc index 4da3917..bd84fa3 100644 --- a/ui/views/controls/scroll_view_unittest.cc +++ b/ui/views/controls/scroll_view_unittest.cc
@@ -1654,8 +1654,9 @@ EXPECT_TRUE(compositor); // But setting on the impl side should fail since the layer isn't committed. - int layer_id = container->layer()->cc_layer_for_testing()->id(); - EXPECT_FALSE(compositor->ScrollLayerTo(layer_id, gfx::ScrollOffset(0, 0))); + cc::ElementId element_id = + container->layer()->cc_layer_for_testing()->element_id(); + EXPECT_FALSE(compositor->ScrollLayerTo(element_id, gfx::ScrollOffset(0, 0))); EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset()); WaitForCommit(); @@ -1663,13 +1664,13 @@ // Upon commit, the impl side should report the same value too. gfx::ScrollOffset impl_offset; - EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset)); + EXPECT_TRUE(compositor->GetScrollOffsetForLayer(element_id, &impl_offset)); EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), impl_offset); // Now impl-side scrolling should work, and also update the ScrollView. offset.set_y(kDefaultHeight * 3); EXPECT_TRUE( - compositor->ScrollLayerTo(layer_id, gfx::ScrollOffset(0, offset.y()))); + compositor->ScrollLayerTo(element_id, gfx::ScrollOffset(0, offset.y()))); EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset()); // Scroll via ScrollView API. Should be reflected on the impl side. @@ -1677,7 +1678,7 @@ scroll_view->contents()->ScrollRectToVisible(offset); EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset()); - EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset)); + EXPECT_TRUE(compositor->GetScrollOffsetForLayer(element_id, &impl_offset)); EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), impl_offset); // Test horizontal scrolling. @@ -1686,7 +1687,7 @@ EXPECT_EQ(gfx::ScrollOffset(offset.x(), offset.y()), test_api.CurrentOffset()); - EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset)); + EXPECT_TRUE(compositor->GetScrollOffsetForLayer(element_id, &impl_offset)); EXPECT_EQ(gfx::ScrollOffset(offset.x(), offset.y()), impl_offset); }
diff --git a/ui/views/view_properties.cc b/ui/views/view_properties.cc index d579a16..994fe8c 100644 --- a/ui/views/view_properties.cc +++ b/ui/views/view_properties.cc
@@ -4,6 +4,7 @@ #include "ui/views/view_properties.h" +#include "ui/base/hit_test.h" #include "ui/gfx/geometry/insets.h" #include "ui/views/bubble/bubble_dialog_delegate.h" @@ -19,6 +20,7 @@ namespace views { +DEFINE_UI_CLASS_PROPERTY_KEY(int, kHitTestComponentKey, HTNOWHERE); DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Insets, kMarginsKey, nullptr); DEFINE_UI_CLASS_PROPERTY_KEY(views::BubbleDialogDelegateView*, kAnchoredDialogKey,
diff --git a/ui/views/view_properties.h b/ui/views/view_properties.h index 4e706ec..2896ee9 100644 --- a/ui/views/view_properties.h +++ b/ui/views/view_properties.h
@@ -16,6 +16,10 @@ class BubbleDialogDelegateView; +// The hit test component (e.g. HTCLIENT) for a View in a window frame. Defaults +// to HTNOWHERE. +VIEWS_EXPORT extern const ui::ClassProperty<int>* const kHitTestComponentKey; + // A property to store margins around the outer perimeter of the view. Margins // are outside the bounds of the view. This is used by various layout managers // to position views with the proper spacing between them.
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index e4e7fc6..a4a01235 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc
@@ -836,10 +836,6 @@ return; non_client_view_->UpdateWindowTitle(); - - // If the non-client view is rendering its own title, it'll need to relayout - // now and to get a paint update later on. - non_client_view_->Layout(); } void Widget::UpdateWindowIcon() {
diff --git a/ui/views/window/custom_frame_view.cc b/ui/views/window/custom_frame_view.cc index 22d0bed..0ae8ebd 100644 --- a/ui/views/window/custom_frame_view.cc +++ b/ui/views/window/custom_frame_view.cc
@@ -197,8 +197,12 @@ } void CustomFrameView::UpdateWindowTitle() { - if (frame_->widget_delegate()->ShouldShowWindowTitle()) + if (frame_->widget_delegate()->ShouldShowWindowTitle() && + // If this is still unset, we haven't laid out window controls yet. + maximum_title_bar_x_ > -1) { + LayoutTitleBar(); SchedulePaintInRect(title_bounds_); + } } void CustomFrameView::SizeConstraintsChanged() {
diff --git a/ui/wm/core/window_util.cc b/ui/wm/core/window_util.cc index ec6ec57e..ed0f762 100644 --- a/ui/wm/core/window_util.cc +++ b/ui/wm/core/window_util.cc
@@ -212,15 +212,31 @@ void SnapWindowToPixelBoundary(aura::Window* window) { // TODO(malaykeshav): We want to snap each window layer to its parent window // layer. See https://crbug.com/863268 for more info. - window->SetProperty(wm::kSnapChildrenToPixelBoundary, true); - aura::Window* snapped_ancestor = window->parent(); - while (snapped_ancestor) { - if (snapped_ancestor->GetProperty(wm::kSnapChildrenToPixelBoundary)) { - ui::SnapLayerToPhysicalPixelBoundary(snapped_ancestor->layer(), + + // Root window is already snapped by default. + if (window->IsRootWindow()) { + window->SetProperty(wm::kSnapChildrenToPixelBoundary, true); + return; + } + + aura::Window* ancestor_window = window->parent(); + while (ancestor_window) { + bool is_ancestor_window_snapped = + ancestor_window->GetProperty(wm::kSnapChildrenToPixelBoundary); + + // Root windows are already snapped by default. Just mark them as snapped. + if (ancestor_window->IsRootWindow() && !is_ancestor_window_snapped) { + ancestor_window->SetProperty(wm::kSnapChildrenToPixelBoundary, true); + is_ancestor_window_snapped = true; + } + + if (is_ancestor_window_snapped) { + window->SetProperty(wm::kSnapChildrenToPixelBoundary, true); + ui::SnapLayerToPhysicalPixelBoundary(ancestor_window->layer(), window->layer()); return; } - snapped_ancestor = snapped_ancestor->parent(); + ancestor_window = ancestor_window->parent(); } }
diff --git a/ui/wm/core/window_util_unittest.cc b/ui/wm/core/window_util_unittest.cc index 10de1ca..c9e87e0 100644 --- a/ui/wm/core/window_util_unittest.cc +++ b/ui/wm/core/window_util_unittest.cc
@@ -12,6 +12,7 @@ #include "ui/aura/window.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_tree_owner.h" +#include "ui/wm/core/window_properties.h" namespace wm { @@ -99,4 +100,22 @@ EXPECT_EQ(window12->layer(), window1->layer()->children()[1]); } +// Test if the root window is always snapped. +TEST_F(WindowUtilTest, CheckRootWindowAlwaysSnapped) { + std::unique_ptr<aura::Window> window11( + aura::test::CreateTestWindowWithId(1, root_window())); + std::unique_ptr<aura::Window> window12( + aura::test::CreateTestWindowWithId(2, root_window())); + + EXPECT_TRUE(root_window()->IsRootWindow()); + + wm::SnapWindowToPixelBoundary(window12.get()); + + // Root window is always marked as snapped. + EXPECT_TRUE(root_window()->GetProperty(wm::kSnapChildrenToPixelBoundary)); + + EXPECT_TRUE(window12->GetProperty(wm::kSnapChildrenToPixelBoundary)); + EXPECT_FALSE(window11->GetProperty(wm::kSnapChildrenToPixelBoundary)); +} + } // namespace wm